gpt4 book ai didi

c++ - 仅使用虚拟复制构造函数 move 适应 std::any 的类型是否安全?

转载 作者:行者123 更新时间:2023-12-04 12:44:37 28 4
gpt4 key购买 nike

我想初始化 std::any带有仅 move 类型变量。我找到了 Cannot move 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
}

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
}

https://wandbox.org/permlink/kxEnIslmVnJNRSn6

然后编译成功完成,如我所料。我得到了有趣的输出。
move_only::move_only()
move_only::move_only(move_only &&)

似乎没有调用复制构造函数。这对我来说是令人惊讶的。

我提出了以下包装方法。

添加虚拟复制构造函数包装器
#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));
}

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 &&)

似乎我使用提供虚拟复制构造函数的包装器使用仅 move 类型初始化了 std::any 。如果目标只是使用仅 move 类型初始化 std::any ,则使用 shared_ptr 更有效。这对我来说是预期的行为。

只要我只为 std::any做 move 操作一次 move_only移至 std::any ,这个代码安全吗?
std::any被复制,然后由于wrapped_move_only 的复制构造函数被调用, Assets 失败。我想知道 move 唯一的情况下的安全性。

我也不知道为什么 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)));
}

https://wandbox.org/permlink/guEWPIrK9wiJ3BgW

最佳答案

I am also not sure why std::any's target requires copy constructor but it is not called.


std::any的设计是一种可以容纳任何可复制类型的具体类型。当您复制 std::any ,你复制它下面的任何东西
std::any需要知道如何复制底层对象,而不管它是否真的要被复制(它如何知道是否会发生这种情况?)。因此,如果基础类型不可复制构造,则它必须是编译错误。

但是,当我们构建 std::any 时本身,在这一点上,我们知道我们正在构建的具体对象。如果那个具体对象恰好是一个右值,那么我们可以 move 构造 std::any的底层对象来自构造函数参数而不是复制构造。这是一场免费的胜利。

您的任何代码实际上都没有复制 std::any ,所以它不会调用 std::any的复制构造函数,它将调用底层类型的复制构造函数。

类似的事情发生在 std::function也许这里的区别会更明显。当我构建一个 std::function<void()> ,有一个静态要求,即对象可以不带参数调用。如果不是 invokabe,则是编译错误。

但只需构建 std::function<void()>不会实际调用底层函数 - 这些是单独的操作。您不会期望触发此断言:
std::function<void()> f = []{ assert(false); }

关于c++ - 仅使用虚拟复制构造函数 move 适应 std::any 的类型是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57923561/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com