我有std::vector
一个特定类的对象A
。该类是非平凡的,并且定义了复制构造函数和移动构造函数。
std::vector<A> myvec;
如果我用对象填充向量A
(使用 eg myvec.push_back(a)
),向量的大小会增加,使用复制构造函数A( const A&)
来实例化向量中元素的新副本。
我可以以某种方式强制A
使用类的移动构造函数吗?
我有std::vector
一个特定类的对象A
。该类是非平凡的,并且定义了复制构造函数和移动构造函数。
std::vector<A> myvec;
如果我用对象填充向量A
(使用 eg myvec.push_back(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++ 移动语义和异常
Bo 暗示这可能与例外有关。还可以考虑 Kerrek SB 的建议并emplace_back
尽可能使用。它可以更快(但通常不是),可以更清晰、更紧凑,但也存在一些缺陷(尤其是非显式构造函数)。
编辑,通常默认是你想要的:移动所有可以移动的,复制其余的。要明确要求,请写
A(A && rhs) = default;
这样做,您将尽可能获得 noexcept:默认的 Move 构造函数是否定义为 noexcept?
请注意,早期版本的 Visual Studio 2015 和更早版本不支持这一点,即使它支持移动语义。
有趣的是,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
但是,当我从中删除noexcept
时~foo()
,结果是不同的:
copy
copy
copy
我想这也回答了这个问题。
看来,std::vector
在重新分配上强制使用移动语义的唯一方法(对于 C++17 和早期版本)是删除复制构造函数:)。通过这种方式,它将在编译时使用您的移动构造函数或尝试死亡:)。
有许多规则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;