可以从同一对象复制 elision/RVO 导致 copy/move
Can copy elision/RVO cause a copy/move from the same object
假设我有一个如下所示的函数:
SomeObject copy_maybe(bool make_new, const SomeObject& def)
{
if (make_new)
return SomeObject();
else
return def;
}
我这样称呼它:
SomeObject obj;
obj = copy_maybe(true, obj);
如果没有复制省略,这显然总是会从 copy_maybe
中创建的临时文件复制到 obj
。但是,使用复制 elision/RVO,是否可能从 obj
复制到 obj
?
更具体地说,在这些(或类似)条件下,在复制运算符 (void operator=(SomeObject const &other)
) 中,由于复制省略,this
和 &other
是否可能相同?
我在 Ideone 上创建了一个 test,它 returns 单独的地址,但我只是想确保此行为由规范定义。
However, with copy elision/RVO, is it possible that the copy will happen from obj
to obj
?
否"copy elision/RVO"。
对 "copy will happen from obj
to obj
" 是,但仅作为复制作业。
建议检查用户定义的复制赋值函数中的自赋值。当您这样做时,您的代码应该可以正常工作。
SomeObject& operator=(SomeObject const& rhs)
{
// Do nothing for self assignment.
if ( this != &rhs )
{
...
}
return *this;
}
However, with copy elision/RVO, is it possible that the copy will happen from obj
to obj
?
没有。 Copy elison/RVO 用于初始化一个变量的过程。由于您已经使用 SomeObject obj;
初始化了 obj
,因此您不会得到任何优化。复制赋值运算符将被调用,调用站点的 obj
将被分配函数中 obj
的值。
如果你有
SomeObject obj = copy_maybe(true, obj);
那么是的,复制 elison 可以(将在 C++17 中)发挥作用。
请注意调用
SomeObject obj = copy_maybe(false, obj);
将使 obj
处于不确定状态,因为它与
相同
SomeObject obj = obj;
Copy/move assignments 永远不能省略;省略仅在对象初始化时发生。
但是,有一种方法可以使省略应用于现有对象:
SomeObject obj;
new(&obj) auto(copy_maybe(false, obj);
C++17 以一种有趣的方式定义了这一点。放置 new
发生在构建新对象之前。该对象的放置 new
调用被称为 "obtain storage"。
并且标准规定,当您对一个对象 "obtain storage" 时,该存储中已经存在的任何对象的生命周期都将终止(因为它们的存储被重新用于新对象)。因此,最初声明的对象的生命周期结束了。但是它的 destructor 没有被调用;如果您的程序依赖于在对象生命周期结束之前调用的析构函数,那么您就有了 UB。
但这无论如何都会激怒UB。为什么?因为 obj
的生命周期在 之前结束 copy_maybe
被调用。因此 copy_maybe
将获得对不再存在的对象的引用。当 copy_maybe
访问对 non-existent 对象的引用时,你会得到 UB。
同理:
SomeObject obj = copy_maybe(false, obj);
这也招惹了UB。 obj
的初始化为non-vacuuous;因此,它的生命周期直到它的初始化完成才开始。这发生在 copy_maybe
。但是 copy_maybe
被赋予了对尚未开始生命周期的对象的引用。那是UB。
假设我有一个如下所示的函数:
SomeObject copy_maybe(bool make_new, const SomeObject& def)
{
if (make_new)
return SomeObject();
else
return def;
}
我这样称呼它:
SomeObject obj;
obj = copy_maybe(true, obj);
如果没有复制省略,这显然总是会从 copy_maybe
中创建的临时文件复制到 obj
。但是,使用复制 elision/RVO,是否可能从 obj
复制到 obj
?
更具体地说,在这些(或类似)条件下,在复制运算符 (void operator=(SomeObject const &other)
) 中,由于复制省略,this
和 &other
是否可能相同?
我在 Ideone 上创建了一个 test,它 returns 单独的地址,但我只是想确保此行为由规范定义。
However, with copy elision/RVO, is it possible that the copy will happen from
obj
toobj
?
否"copy elision/RVO"。
对 "copy will happen from obj
to obj
" 是,但仅作为复制作业。
建议检查用户定义的复制赋值函数中的自赋值。当您这样做时,您的代码应该可以正常工作。
SomeObject& operator=(SomeObject const& rhs)
{
// Do nothing for self assignment.
if ( this != &rhs )
{
...
}
return *this;
}
However, with copy elision/RVO, is it possible that the copy will happen from
obj
toobj
?
没有。 Copy elison/RVO 用于初始化一个变量的过程。由于您已经使用 SomeObject obj;
初始化了 obj
,因此您不会得到任何优化。复制赋值运算符将被调用,调用站点的 obj
将被分配函数中 obj
的值。
如果你有
SomeObject obj = copy_maybe(true, obj);
那么是的,复制 elison 可以(将在 C++17 中)发挥作用。
请注意调用
SomeObject obj = copy_maybe(false, obj);
将使 obj
处于不确定状态,因为它与
SomeObject obj = obj;
Copy/move assignments 永远不能省略;省略仅在对象初始化时发生。
但是,有一种方法可以使省略应用于现有对象:
SomeObject obj;
new(&obj) auto(copy_maybe(false, obj);
C++17 以一种有趣的方式定义了这一点。放置 new
发生在构建新对象之前。该对象的放置 new
调用被称为 "obtain storage"。
并且标准规定,当您对一个对象 "obtain storage" 时,该存储中已经存在的任何对象的生命周期都将终止(因为它们的存储被重新用于新对象)。因此,最初声明的对象的生命周期结束了。但是它的 destructor 没有被调用;如果您的程序依赖于在对象生命周期结束之前调用的析构函数,那么您就有了 UB。
但这无论如何都会激怒UB。为什么?因为 obj
的生命周期在 之前结束 copy_maybe
被调用。因此 copy_maybe
将获得对不再存在的对象的引用。当 copy_maybe
访问对 non-existent 对象的引用时,你会得到 UB。
同理:
SomeObject obj = copy_maybe(false, obj);
这也招惹了UB。 obj
的初始化为non-vacuuous;因此,它的生命周期直到它的初始化完成才开始。这发生在 copy_maybe
。但是 copy_maybe
被赋予了对尚未开始生命周期的对象的引用。那是UB。