I'v read the documentation for QObject::connect (for Qt 5.4), but I have a question about the overload
我阅读了QObject::connect (qt5.4)的文档,但是我有一个关于过载的问题。
QMetaObject::Connection QObject::connect(const QObject * sender, PointerToMemberFunction signal, const QObject * context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)
QMetaObject::连接QObject::connect(const QObject * sender, PointerToMemberFunction signal, const QObject * context, Functor Functor, Qt::ConnectionType = Qt::AutoConnection)
What exactly is the context
parameter? What is its purpose? Can it be used to build connections in local event loops in threads?
上下文参数究竟是什么?它的目的是什么?它可以用于在线程中构建本地事件循环中的连接吗?
Can someone provide examples of how/when to use this overload (when the context is not this
)?
有人能提供如何/何时使用这个重载的示例吗(当上下文不是这个时)?
1 个解决方案
#1
15
The context object is used in two scenarios.
上下文对象在两种场景中使用。
Automatic disconnection
Let's first do a step back and ask ourselves: when does Qt break a connection?
让我们先退一步,问问自己:Qt什么时候断开连接?
With the usual connect(sender, signal, receiver, slot)
connect, there are three possibilities:
通过通常的连接(发送方、信号、接收方、插槽),有三种可能:
- When someone explicitely calls
disconnect
; - 当某人明确地呼叫断开;
- When
sender
is deleted; - 当发送者被删除;
- When
receiver
is deleted. - 当接收器被删除。
Especially in cases #2 and #3, it just makes sense for Qt to behave that way (actually, it must behave that way, otherwise you'd have resource leaks and/or crashes).
特别是在#2和#3的情况下,Qt这样做是有意义的(实际上,它必须这样做,否则会出现资源泄漏和/或崩溃)。
Now: when using the connect
overload taking a functor, when does Qt break a connection?
现在:当使用带函子的连接重载时,Qt何时中断连接?
Note that without the context
parameter, there's only one QObject involved: the sender. Hence the answer is:
注意,没有上下文参数,只涉及一个QObject: sender。因此,答案是:
- When someone explicitely calls
disconnect
; - 当某人明确地呼叫断开;
- When
sender
is deleted. - 当发送者删除。
Of course, there's no receiver object here! So only the sender automatically controls the lifetime of a connection.
当然,这里没有接收对象!因此只有发送方自动控制连接的生命周期。
Now, the problem is that the functor may capture some extra state that can become invalid, in which case is desirable that the connection gets broken automatically. The typical case is with lambdas:
现在的问题是,函数器可能捕获一些可能无效的额外状态,在这种情况下,需要自动断开连接。典型的例子是lambdas:
connect(sender, &Sender::signal,
[&object1, &object2](Param p)
{
use(object1, object2, p);
}
);
What happens if object1
or object2
get deleted? The connection will still be alive, therefore emitting the signal will still invoke the lambda, which in turn will access destroyed objects. And that's kind of bad...
如果object1或object2被删除会发生什么?连接仍然是活动的,因此发送信号仍然调用lambda,进而访问被破坏的对象。这有点糟糕……
For this reason, when it comes to functors, a connect
overload taking a context object has been introduced. A connection established using that overload will be disconnected automatically also
由于这个原因,当涉及到函数函数时,引入了一个获取上下文对象的连接重载。使用该重载建立的连接也将自动断开
- when the
context
object is deleted. - 当上下文对象被删除时。
You're probably right when you say that a good number of times you're going to see there the very same "main" object used in the functor, for instance
你可能是对的,当你说很多次你会看到在函数中使用相同的“主”对象,例如。
connect(button,
&QPushButton::clicked,
otherWidget,
[otherWidget]()
{
otherWidget->doThis(); otherWidget->doThat();
}
);
That's just a pattern in Qt -- when setting up connections for sub-objects, you typically connect them to slots on this
object, hence this
is probably the most common context. However, in general, you may also end up with something like
这只是Qt中的一种模式——在为子对象设置连接时,通常会将它们连接到该对象的slot,因此这可能是最常见的上下文。然而,总的来说,您可能会得到类似的结果
// manages the lifetime of the resources; they will never outlive this object
struct ResourceManager : QObject
{
Resource res1; // non-QObjects
OtherResource res2;
};
ResourceManager manager;
connect(sender, signal, manager, [&manager](){ use(manager.res1, ...); });
// or, directly capture the resources, not the handle
So, you're capturing part of the state of manager
.
所以,你捕获了一部分管理者的状态。
In the most general case, when no context
object is available, if there's the chance that the objects captured by the lambda survive the connection, then you must capture them by weak pointers, and try to lock those pointers inside the lambda before trying to access them.
在最一般的情况下,当没有上下文对象可用时,如果lambda捕获的对象在连接中幸存,那么必须通过弱指针捕获它们,并尝试在试图访问它们之前将这些指针锁定在lambda中。
Running a functor in a specific thread/event loop
Very shortly: when specifying a context object, the functor will be run into the context's thread, just like normal connections employing a receiver object. Indeed, note that the connect
overload that takes a context also takes a connection type (while the one without context doesn't take one -- connection is always direct).
很短的时间:在指定上下文对象时,函数将会被运行到上下文的线程中,就像使用接收对象的正常连接一样。的确,请注意,接受上下文的连接重载也接受连接类型(而没有上下文的连接不接受连接类型——连接总是直接的)。
Again, this is useful because QObject is not reentrant or thread safe, and you must use a QObject only in the thread it lives in. If your functor accesses an object living in another thread, it must be executed in that thread; specifying that object as the context solves the issue.
同样,这是有用的,因为QObject不是可重入的或线程安全的,并且您必须仅在它所处的线程中使用一个QObject。如果您的函子访问位于另一个线程中的对象,则必须在该线程中执行该对象;将该对象指定为上下文可以解决问题。
#1
15
The context object is used in two scenarios.
上下文对象在两种场景中使用。
Automatic disconnection
Let's first do a step back and ask ourselves: when does Qt break a connection?
让我们先退一步,问问自己:Qt什么时候断开连接?
With the usual connect(sender, signal, receiver, slot)
connect, there are three possibilities:
通过通常的连接(发送方、信号、接收方、插槽),有三种可能:
- When someone explicitely calls
disconnect
; - 当某人明确地呼叫断开;
- When
sender
is deleted; - 当发送者被删除;
- When
receiver
is deleted. - 当接收器被删除。
Especially in cases #2 and #3, it just makes sense for Qt to behave that way (actually, it must behave that way, otherwise you'd have resource leaks and/or crashes).
特别是在#2和#3的情况下,Qt这样做是有意义的(实际上,它必须这样做,否则会出现资源泄漏和/或崩溃)。
Now: when using the connect
overload taking a functor, when does Qt break a connection?
现在:当使用带函子的连接重载时,Qt何时中断连接?
Note that without the context
parameter, there's only one QObject involved: the sender. Hence the answer is:
注意,没有上下文参数,只涉及一个QObject: sender。因此,答案是:
- When someone explicitely calls
disconnect
; - 当某人明确地呼叫断开;
- When
sender
is deleted. - 当发送者删除。
Of course, there's no receiver object here! So only the sender automatically controls the lifetime of a connection.
当然,这里没有接收对象!因此只有发送方自动控制连接的生命周期。
Now, the problem is that the functor may capture some extra state that can become invalid, in which case is desirable that the connection gets broken automatically. The typical case is with lambdas:
现在的问题是,函数器可能捕获一些可能无效的额外状态,在这种情况下,需要自动断开连接。典型的例子是lambdas:
connect(sender, &Sender::signal,
[&object1, &object2](Param p)
{
use(object1, object2, p);
}
);
What happens if object1
or object2
get deleted? The connection will still be alive, therefore emitting the signal will still invoke the lambda, which in turn will access destroyed objects. And that's kind of bad...
如果object1或object2被删除会发生什么?连接仍然是活动的,因此发送信号仍然调用lambda,进而访问被破坏的对象。这有点糟糕……
For this reason, when it comes to functors, a connect
overload taking a context object has been introduced. A connection established using that overload will be disconnected automatically also
由于这个原因,当涉及到函数函数时,引入了一个获取上下文对象的连接重载。使用该重载建立的连接也将自动断开
- when the
context
object is deleted. - 当上下文对象被删除时。
You're probably right when you say that a good number of times you're going to see there the very same "main" object used in the functor, for instance
你可能是对的,当你说很多次你会看到在函数中使用相同的“主”对象,例如。
connect(button,
&QPushButton::clicked,
otherWidget,
[otherWidget]()
{
otherWidget->doThis(); otherWidget->doThat();
}
);
That's just a pattern in Qt -- when setting up connections for sub-objects, you typically connect them to slots on this
object, hence this
is probably the most common context. However, in general, you may also end up with something like
这只是Qt中的一种模式——在为子对象设置连接时,通常会将它们连接到该对象的slot,因此这可能是最常见的上下文。然而,总的来说,您可能会得到类似的结果
// manages the lifetime of the resources; they will never outlive this object
struct ResourceManager : QObject
{
Resource res1; // non-QObjects
OtherResource res2;
};
ResourceManager manager;
connect(sender, signal, manager, [&manager](){ use(manager.res1, ...); });
// or, directly capture the resources, not the handle
So, you're capturing part of the state of manager
.
所以,你捕获了一部分管理者的状态。
In the most general case, when no context
object is available, if there's the chance that the objects captured by the lambda survive the connection, then you must capture them by weak pointers, and try to lock those pointers inside the lambda before trying to access them.
在最一般的情况下,当没有上下文对象可用时,如果lambda捕获的对象在连接中幸存,那么必须通过弱指针捕获它们,并尝试在试图访问它们之前将这些指针锁定在lambda中。
Running a functor in a specific thread/event loop
Very shortly: when specifying a context object, the functor will be run into the context's thread, just like normal connections employing a receiver object. Indeed, note that the connect
overload that takes a context also takes a connection type (while the one without context doesn't take one -- connection is always direct).
很短的时间:在指定上下文对象时,函数将会被运行到上下文的线程中,就像使用接收对象的正常连接一样。的确,请注意,接受上下文的连接重载也接受连接类型(而没有上下文的连接不接受连接类型——连接总是直接的)。
Again, this is useful because QObject is not reentrant or thread safe, and you must use a QObject only in the thread it lives in. If your functor accesses an object living in another thread, it must be executed in that thread; specifying that object as the context solves the issue.
同样,这是有用的,因为QObject不是可重入的或线程安全的,并且您必须仅在它所处的线程中使用一个QObject。如果您的函子访问位于另一个线程中的对象,则必须在该线程中执行该对象;将该对象指定为上下文可以解决问题。