当向量增长时如何强制移动语义?
我有一个特定类 A
的对象的 std::vector
。该类非常重要,并且定义了复制构造函数和移动构造函数。
std::vector<A> myvec;
如果我用 A
对象填充向量(例如使用 myvec.push_back(a)
),则使用复制构造函数 A,向量的大小将会增加( const A&)
实例化向量中元素的新副本。
我可以以某种方式强制使用类 A
的移动构造函数吗?
I have a std::vector
of objects of a certain class A
. The class is non-trivial and has copy constructors and move constructors defined.
std::vector<A> myvec;
If I fill-up the vector with A
objects (using e.g. myvec.push_back(a)
), the vector will grow in size, using the copy constructor A( const A&)
to instantiate new copies of the elements in the vector.
Can I somehow enforce that the move constructor of class A
is beging used instead?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您需要使用
noexcept
通知 C++(特别是std::vector
)您的移动构造函数和析构函数不会抛出异常。然后当向量增长时将调用移动构造函数。这是声明和实现
std::vector
所遵循的移动构造函数的方法:如果构造函数不是
noexcept
,则std::vector
> 不能使用它,因为这样就不能确保标准所要求的异常保证。有关标准中所述内容的更多信息,请阅读
C++ Move 语义和异常
感谢 Bo,他暗示这可能与异常有关。另请考虑 Kerrek SB 的建议,并尽可能使用
emplace_back
。它可以更快(但通常不是),它可以更清晰、更紧凑,但也存在一些陷阱(特别是对于非显式构造函数)。编辑,通常默认就是您想要的:移动所有可以移动的内容,复制其余的。要明确要求,请写
Doing that, you will get no except if possible: 默认的 Move 构造函数是否定义为 noexcept?
请注意,Visual Studio 2015 及更早版本的早期版本不支持这一点,尽管它支持移动语义。
You need to inform C++ (specifically
std::vector
) that your move constructor and destructor does not throw, usingnoexcept
. Then the move constructor will be called when the vector grows.This is how to declare and implement a move constuctor that is respected by
std::vector
:If the constructor is not
noexcept
,std::vector
can't use it, since then it can't ensure the exception guarantees demanded by the standard.For more about what's said in the standard, read
C++ Move semantics and Exceptions
Credit to Bo who hinted that it may have to do with exceptions. Also consider Kerrek SB's advice and use
emplace_back
when possible. It can be faster (but often is not), it can be clearer and more compact, but there are also some pitfalls (especially with non-explicit constructors).Edit, often the default is what you want: move everything that can be moved, copy the rest. To explicitly ask for that, write
Doing that, you will get noexcept when possible: Is the default Move constructor defined as noexcept?
Note that early versions of Visual Studio 2015 and older did not support that, even though it supports move semantics.
有趣的是,如果移动构造函数和析构函数都是
noexcept
,则 gcc 4.7.2 的向量仅使用移动构造函数。一个简单的例子:这输出了预期的结果:
但是,当我从
~foo()
中删除noexcept
时,结果不同:我想这也回答了 这个问题。
Interestingly, gcc 4.7.2's vector only uses move constructor if both the move constructor and the destructor are
noexcept
. A simple example:This outputs the expected:
However, when I remove
noexcept
from~foo()
, the result is different:I guess this also answers this question.
看来,强制
std::vector
在重新分配时使用移动语义的唯一方法(对于 C++17 及早期版本)是删除复制构造函数:)。通过这种方式,它将在编译时使用您的移动构造函数或尝试失败:)。有许多规则规定 std::vector 不得在重新分配时使用移动构造函数,但没有规定在何处必须使用它。
直播
或
实时代码
您的
T
类必须具有noexcept
移动构造函数/赋值运算符和noexcept
析构函数。否则你会得到编译错误。It seems, that the only way (for C++17 and early), to enforce
std::vector
use move semantics on reallocation is deleting copy constructor :) . In this way it will use your move constructors or die trying, at compile time :).There are many rules where
std::vector
MUST NOT use move constructor on reallocation, but nothing about where it MUST USE it.Live
or
Live code
Your
T
class must havenoexcept
move constructor/assigment operator andnoexcept
destructor. Otherwise you'll get compilation error.