Tak*_*ndo 7 c++ move c++17 stdany
我想std::any使用仅移动类型变量进行初始化。我发现无法移动std :: any。
在通过链接的答案使用shared_ptr解决方法之前,我测试了以下代码:
#include <utility>
#include <iostream>
#include <any>
struct move_only {
move_only() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
move_only(move_only const&) = delete;
move_only(move_only &&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main() {
move_only m;
std::any a(std::move(m)); // error. copy constructor is required
}
Run Code Online (Sandbox Code Playgroud)
https://wandbox.org/permlink/h6HOSdgOnQYg4a6K
上面的代码由于move_only没有复制构造函数而输出编译错误。
我添加了复制构造函数进行测试。
#include <utility>
#include <iostream>
#include <any>
struct move_only {
move_only() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
move_only(move_only const&) {
// not called
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
move_only(move_only &&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main() {
move_only m;
std::any a(std::move(m)); // success but copy constructor is not called
}
Run Code Online (Sandbox Code Playgroud)
https://wandbox.org/permlink/kxEnIslmVnJNRSn6
然后编译成功完成。我得到了有趣的输出。
move_only::move_only()
move_only::move_only(move_only &&)
Run Code Online (Sandbox Code Playgroud)
似乎没有调用复制构造函数。我感到惊讶。
我想出了以下包装方法。
#include <utility>
#include <iostream>
#include <any>
struct move_only {
move_only() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
move_only(move_only const&) = delete;
move_only(move_only &&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
struct wrapped_move_only : move_only {
wrapped_move_only(move_only&& m):move_only(std::move(m)) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
wrapped_move_only(wrapped_move_only const&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
assert(false);
}
wrapped_move_only(wrapped_move_only &&) = default;
};
int main() {
move_only m;
wrapped_move_only wmo(std::move(m));
std::any a(std::move(wmo));
}
Run Code Online (Sandbox Code Playgroud)
https://wandbox.org/permlink/EDhq3KPWKP9fCA9v
move_only的副本构造函数将被删除。wapped_move_only类继承了move_only并添加了副本构造函数。
它编译成功,得到以下结果。
move_only::move_only()
move_only::move_only(move_only &&)
wrapped_move_only::wrapped_move_only(move_only &&)
move_only::move_only(move_only &&)
Run Code Online (Sandbox Code Playgroud)
似乎我使用提供伪拷贝构造函数的包装器以仅移动类型初始化了std :: any。如果目标只是使用仅移动类型初始化std :: any,则使用shared_ptr效率更高。这是我的预期行为。
只要我仅将操作std::any一次move_only移动到std::any,此代码安全吗?如果std::any被复制,则资产失败,因为调用了wrapd_move_only的复制构造函数。我想知道仅移动案件的安全性。
我也不确定为什么std::any目标需要复制构造函数,但未调用它。
如果安全的话,我可以使用模板来改进这种方法。模板add_dummy_copy_constructor是一种适配器。
#include <utility>
#include <iostream>
#include <any>
struct move_only {
move_only() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
move_only(move_only const&) = delete;
move_only(move_only &&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
template <typename T>
struct add_dummy_copy_constructor : T {
add_dummy_copy_constructor(T&& t):T(std::move(t)) {}
add_dummy_copy_constructor(add_dummy_copy_constructor const&) {
assert(false);
}
add_dummy_copy_constructor(add_dummy_copy_constructor &&) = default;
};
int main() {
move_only m;
std::any a(add_dummy_copy_constructor(std::move(m)));
}
Run Code Online (Sandbox Code Playgroud)
我也不确定为什么
std::any's target 需要复制构造函数但它没有被调用。
的设计std::any是一种可以容纳任何可复制类型的具体类型。当你复制 a 时std::any,你复制了它下面的任何内容
需要std::any知道如何复制底层对象,无论它是否真的会被复制(它如何知道这是否会发生?)。因此,如果基础类型不可复制构造,则一定是编译错误。
然而,当我们构建std::any自身时,我们就知道我们正在构建的具体对象。如果该具体对象恰好是右值,那么我们可以从构造函数参数移动构造的std::any基础对象,而不是复制构造。这是一场免费的胜利。
您的代码实际上都没有复制 a std::any,因此它们都不会调用 的std::any复制构造函数,而该复制构造函数将调用基础类型的复制构造函数。
类似的事情发生了std::function,也许这里的区别会更明显。当我构造 a 时std::function<void()>,有一个静态要求,即该对象可以在没有参数的情况下调用。如果不调用则编译错误。
但简单地构造std::function<void()>will 实际上不会调用底层函数 - 这些是单独的操作。您不会期望触发此断言:
std::function<void()> f = []{ assert(false); }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
97 次 |
| 最近记录: |