用相同类型的新对象覆盖对象并使用 this 闭包
在以下代码中,一个对象被相同类型的新对象覆盖,其中 lambda 表达式创建一个使用旧对象的 this
的闭包。旧地址 (this
) 保持不变,新对象具有相同的布局,所以这应该没问题,而不是 UB。但是对于不平凡的对象或其他情况呢?
struct A {
void g(A& o, int v) {
o = A{.x = v, .f = [this]{
std::cout << "f" << this->x << '\n';
}};
}
int x{0};
std::function<void()> f;
~A() {
std::cout << "dtor" << x << '\n';
}
};
void test() {
A a;
a.g(a, 2);
a.f();
}
In the following code an object is overwritten with a new object of same type, where a lambda-expression creates a closure that uses this
of the old object. The old address (this
) remains the same, the new object has the same layout, so this should be ok and not UB. But what about non trivial objects or other cases?
struct A {
void g(A& o, int v) {
o = A{.x = v, .f = [this]{
std::cout << "f" << this->x << '\n';
}};
}
int x{0};
std::function<void()> f;
~A() {
std::cout << "dtor" << x << '\n';
}
};
void test() {
A a;
a.g(a, 2);
a.f();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您实际上并没有替换任何对象。您只是将另一个对象分配给当前对象。
o =
只是调用隐式复制赋值运算符,该运算符将从使用A{...} 的赋值表达式构造的临时
。A
中复制赋值各个成员。lambda 将从
g
中的this
捕获this
,而不是从临时对象。std::function
将始终保留引用调用g
的原始对象的 lambda 副本,并且由于那是其父对象,因此它的寿命不能超过它。所以这里没有问题。唯一的例外是在销毁
A
对象期间调用f
,在这种情况下,可能会禁止使用捕获的指针。You are not actually replacing any object. You are just assigning from another object to the current one.
o =
simply calls the implicit copy assignment operator which will copy-assign the individual members from the temporaryA
constructed in the assignment expression withA{...}
.The lambda is going to capture
this
fromthis
ing
, not from the temporary object.std::function
will always keep a copy of the lambda referring to the original object on whichg
was called and since that is its parent object, it cannot outlive it.So there is no problem here. The only exception would be that you call
f
during the destruction of theA
object, in which case using the captured pointer may be forbidden.这是一个稍微修改过的代码,带有一个极端情况。我在函数中创建一个临时对象,并对其调用
g
并传递给它一个更永久的对象。临时对象消失了,长寿命对象现在有一个闭包来引用寿命结束后的对象。调用f
is UB:输出为:
证明
af()
的调用在被销毁后尝试使用地址0135FA30处的对象(在该特定运行中) 。Here is a slightly modified code with a corner case. I create a temporary in a function and call
g
on it passing it a more permanent object. The temporary vanishes and the long life object now has a closure refering to an object after its end of life. Invokingf
is UB:The output is:
proving that the invocation of
a.f()
tried to use the object at address 0135FA30 (in that specific run) after it has been destroyed.