我有一个特定类别 A
的对象 std::vector
。该类别是非平凡的,具有定义的复制构造函数 和 移动构造函数。
std::vector<A> myvec;
如果我使用myvec.push_back(a)
向vector中添加A
对象,它的大小会增长,并使用复制构造函数A( const A&)
来实例化向量中元素的新副本。我能否以某种方式强制使用类
A
的移动构造函数?我有一个特定类别 A
的对象 std::vector
。该类别是非平凡的,具有定义的复制构造函数 和 移动构造函数。
std::vector<A> myvec;
如果我使用myvec.push_back(a)
向vector中添加A
对象,它的大小会增长,并使用复制构造函数A( const A&)
来实例化向量中元素的新副本。A
的移动构造函数?你需要告诉 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...
}
如果构造函数不是noexcept
,std::vector
无法使用它,因为这样它无法确保标准所要求的异常保证。如需了解更多有关标准的内容,请阅读C++ Move semantics and Exceptions。
感谢 Bo 提示这可能与异常有关。同时请考虑 Kerrek SB 的建议,在可能的情况下使用 emplace_back
。它可能会更快(但通常不是),也可以更清晰、更简洁,但也存在一些陷阱(特别是对于非显式构造函数)。
编辑,通常默认值就是您想要的:移动所有可移动的内容,复制其余的内容。要明确请求,请编写:A(A && rhs) = default;
这样做,你将在可能的情况下获得noexcept:默认的移动构造函数是否被定义为noexcept?
请注意,早期版本的Visual Studio 2015和更早版本不支持此功能,尽管它支持移动语义。
value_type
的移动构造函数是否为noexcept
?也许语言在调用范围也是noexcept
函数时限制了函数调用候选集合? - Lightness Races in Orbitnoexcept
移动构造函数。如果存在nothrow
复制构造函数,则is_nothrow_move_constructible
将为true。我不知道是否存在昂贵的nothrow
复制构造函数的真实情况,因此它是否真的很重要并不清楚。 - Johan Lundbergpush_back()
调用上使用了std::move()
。有时候你会为了寻找问题而努力地看着它,却没有看到明显的错误就在你面前。然后就到了午餐时间,我忘记删除我的评论了。 - AlastairG有趣的是,gcc 4.7.2的向量(vector)只有在移动构造函数和析构函数都是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
我想这也回答了这个问题。
看起来, (对于 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
移动构造函数/赋值运算符和 noexcept
析构函数。否则会导致编译错误。
std::vector<move_only<MyClass>> vec;