我有某一类A
的对象std::vector
。类是不平凡的,有拷贝构造函数和定义移动的构造。如何在矢量增长时执行移动语义?
std::vector<A> myvec;
如果我填充了A
对象载体(使用例如myvec.push_back(a)
),矢量的大小将增加,使用拷贝构造A(const A&)
实例化于载体的元素的新副本。
我可以采用某种强制执行A
类的移动构造函数beging代替?
我有某一类A
的对象std::vector
。类是不平凡的,有拷贝构造函数和定义移动的构造。如何在矢量增长时执行移动语义?
std::vector<A> myvec;
如果我填充了A
对象载体(使用例如myvec.push_back(a)
),矢量的大小将增加,使用拷贝构造A(const A&)
实例化于载体的元素的新副本。
我可以采用某种强制执行A
类的移动构造函数beging代替?
您需要通知C++(特别是std::vector
)您的移动构造函数和析构函数不会抛出,使用noexcept
。然后,移动构造函数将在矢量增长时被调用。
这是如何声明和实现是由std::vector
尊重的举动constuctor:
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...
}
如果构造不是noexcept
,std::vector
不能用了,从此再不能保证例外保证标准要求。
更多关于什么标准说,读 C++ Move semantics and Exceptions
信用博谁暗示它可能有例外的事情。如果可能,也考虑Kerrek SB的建议并使用emplace_back
。它可以更快(但通常不是),它可以更清晰,更紧凑,但也有一些缺陷(尤其是与非显式构造函数)。
编辑,通常默认是你想要的:移动一切可以移动的,复制剩下的。 Is the default Move constructor defined as noexcept?
注意的Visual Studio 2015年及以上的早期版本不支持,尽管它支持移动语义:要明确要求的是,写
A(A && rhs) = default;
这样做,你会尽可能得到noexcept 。
注意:'throw()'不推荐使用,而是使用'noexcept'。 –
@MatthieuM。啊,是的 - 现在解决了。发现得好。 –
出于兴趣,如何_does_ impl“知道”value_type的move ctor是否是'noexcept'?当调用范围也是'noexcept'函数时,语言是否可以限制函数调用候选集呢? –
有趣的是,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();
}
它输出的预期:
move
move
move
然而,当我从~foo()
删除noexcept
,其结果是不同的:
copy
copy
copy
我想这也回答this question 。
在我看来,其他答案只谈移动构造函数,而不是关于_destructor_必须是noexcept。 –
好点,但是析构函数在默认情况下是noexcept。 –
呃,应该是,但事实证明,在gcc 4.7.2中并不是这样。所以这个问题实际上只针对gcc。不过,它应该在gcc 4.8.0中修复。参见[相关的stackoverflow问题](http://stackoverflow.com/questions/15721544/destructors-and-noexcept)。 –
看来,只有这样(对于C++ 17和早期版本),强制执行std::vector
在重新分配时使用移动语义是删除复制构造函数:)。通过这种方式,它将使用你的移动构造函数或在编译时尝试:)。
有许多规章制度std::vector
绝不能使用在重新分配移动构造函数,但没有关于它必须使用方法它。
template<class T>
class move_only : public T{
public:
move_only(){}
move_only(const move_only&) = delete;
move_only(move_only&&) noexcept {};
~move_only() noexcept {};
using T::T;
};
或
template<class T>
struct move_only{
T value;
template<class Arg, class ...Args, typename = std::enable_if_t<
!std::is_same_v<move_only<T>&&, Arg >
&& !std::is_same_v<const move_only<T>&, Arg >
>>
move_only(Arg&& arg, Args&&... args)
:value(std::forward<Arg>(arg), std::forward<Args>(args)...)
{}
move_only(){}
move_only(const move_only&) = delete;
move_only(move_only&& other) noexcept : value(std::move(other.value)) {};
~move_only() noexcept {};
};
你T
类必须有noexcept
移动构造函数/分配新建分配FY运营商和noexcept
析构函数。否则,你会得到编译错误。
std::vector<move_only<MyClass>> vec;
您可以通过使用移动感知向量执行。 –
你可以请更具体的如何做到这一点? –
您只需使用移动感知矢量实现。这听起来像你的标准库实现(这是它的btw?)不移动感知。您可以尝试使用Boost的移动感知容器。 –