Ber*_*est 82 c++ resize vector move-semantics c++11
我有一个std::vector
特定类的对象A
.该类非常重要,并且定义了复制构造函数和移动构造函数.
std::vector<A> myvec;
Run Code Online (Sandbox Code Playgroud)
如果我用A
对象填充向量(使用例如myvec.push_back(a)
),则向量将增大,使用复制构造函数A( const A&)
来实例化向量中元素的新副本.
我可以以某种方式强制执行类的移动构造函数A
而不是使用它吗?
Joh*_*erg 115
您需要通知C++(特别是std::vector
)您的移动构造函数和析构函数不会抛出,使用noexcept
.然后在向量增长时调用移动构造函数.
这是如何声明和实现一个受以下因素尊重的移动构造函数std::vector
:
A(A && rhs) noexcept {
std::cout << "i am the move constr" <<std::endl;
... some code doing the move ...
m_value=std::move(rhs.m_value) ; // etc...
}
Run Code Online (Sandbox Code Playgroud)
如果构造函数不是noexcept
,std::vector
则不能使用它,因为它不能确保标准所要求的异常保证.
有关标准中所述内容的更多信息,请阅读 C++ Move语义和异常
感谢Bo,他暗示这可能与例外情况有关.另请考虑Kerrek SB的建议和使用emplace_back
.它可以更快(但通常不是),它可以更清晰,更紧凑,但也有一些陷阱(特别是对于非显式构造函数).
编辑,通常默认是您想要的:移动可移动的所有内容,复制其余内容.要明确要求,写
A(A && rhs) = default;
Run Code Online (Sandbox Code Playgroud)
这样做,你将在可能的情况下得到noexcept:默认的Move构造函数是否被定义为noexcept?
请注意,Visual Studio 2015及更早版本的早期版本不支持该版本,即使它支持移动语义.
Nik*_*nes 17
有趣的是,如果移动构造函数和析构函数都是,则gcc 4.7.2的向量仅使用移动构造函数noexcept
.一个简单的例子:
struct foo {
foo() {}
foo( const foo & ) noexcept { std::cout << "copy\n"; }
foo( foo && ) noexcept { std::cout << "move\n"; }
~foo() noexcept {}
};
int main() {
std::vector< foo > v;
for ( int i = 0; i < 3; ++i ) v.emplace_back();
}
Run Code Online (Sandbox Code Playgroud)
这输出了预期的:
move
move
move
Run Code Online (Sandbox Code Playgroud)
但是,当我删除noexcept
时~foo()
,结果是不同的:
copy
copy
copy
Run Code Online (Sandbox Code Playgroud)
我想这也回答了这个问题.