gpt4 book ai didi

c++ - std::vector::push_back 不可复制对象给出编译器错误

转载 作者:可可西里 更新时间:2023-11-01 17:35:35 24 4
gpt4 key购买 nike

我在 g++ (GCC) 4.7.2 上遇到编译错误但不在MSVC-2012当试图 std::vector::push_back不可复制(私有(private)复制构造函数)但可移动的对象。对我来说,我的示例看起来与 SO 和其他地方的许多其他示例相同。错误消息使它看起来像是结构不是“可直接构造”的问题 - 我不知道这意味着什么,所以我加倍不确定为什么对象需要“可直接构造”才能被推回。

#include <vector>
#include <memory>

struct MyStruct
{

MyStruct(std::unique_ptr<int> p);
MyStruct(MyStruct&& other);
MyStruct& operator=(MyStruct&& other);

std::unique_ptr<int> mP;

private:
// Non-copyable
MyStruct(const MyStruct&);
MyStruct& operator=(const MyStruct& other);
};

int main()
{

MyStruct s(std::unique_ptr<int>(new int(5)));
std::vector<MyStruct> v;

auto other = std::move(s); // Test it is moveable
v.push_back(std::move(other)); // Fails to compile

return 0;
}

给出错误

/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/type_traits: In instantiation of ‘struct std::__is_direct_constructible_impl<MyStruct, const MyStruct&>’:
... snip ...
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_vector.h:900:9: required from ‘void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = MyStruct; _Alloc = std::allocator<MyStruct>; std::vector<_Tp, _Alloc>::value_type = MyStruct]’
main.cpp:27:33: required from here
main.cpp:16:5: error: ‘MyStruct::MyStruct(const MyStruct&)’ is private

来自各种答案的简单解决方法:

  • 使用MyStruct(const MyStruct&) = delete;而不是 private ctor破解
  • 继承boost::noncopyable (或另一个有私有(private) Actor 的类(class))

最佳答案

失败是由于 G++ 4.7 的限制,它没有实现 DR 1170。 ,在 C++11 标准化过程中很晚才更改为访问检查应作为模板参数推导的一部分完成。

根本原因是 libstdc++ 的 vector 将移动元素,如果移动操作保证不会抛出(即声明为 noexceptthrow()), 否则如果类型是可复制的元素将被复制, 否则如果类型不可复制但确实有一个可能抛出的移动操作然后它将被移动 (如果抛出异常结果是 undefined 未指定。)这是通过检查 is_nothrow_move_constructibleis_copy_constructible 类型特征来实现的。在您的情况下,该类型不是可构造的,因此检查了 is_copy_constructible 特征。您的类型有一个复制构造函数,但它不可访问,因此 is_copy_constructible 特性会在 G++ 4.7 中产生编译器错误,因为在模板参数推导期间未进行访问检查。

如果你创建你的移动构造函数和移动赋值运算符 noexcept 那么类型将被移动并且不需要可复制,所以失败的 is_copy_constructible 特征是未使用,代码编译正常。

或者,(如注释中所述)如果您删除了复制构造函数,则 is_copy_constructible 特性会得到正确的结果。

另一种选择是使用像 boost::noncopyable 这样的东西,它隐式地删除了复制构造函数,这样 is_copy_constructible 特性就可以正常工作(也可以与旧的编译器一起工作,比如 MSVC不正确支持删除的功能)。我不知道您所说的无法找到错误是什么意思,MSVC 不会向您显示编译器错误的完整上下文吗?

Conclusion: use unique_ptr where appropriate but don't make classes explicitly movable

我不同意这个结论,太极端了。相反,只要有可能,就让你的类不可移动。此外,在可能的情况下,使用已删除的函数来使类型不可复制,而不是私有(private)+未实现的函数,可能使用宏来移植到旧的编译器,例如

#if __cplusplus >= 201103L
#define NONCOPYABLE(TYPE) \
TYPE(const TYPE&) = delete; TYPE& operator=(const TYPE&) = delete
#else
// must be used in private access region
#define NONCOPYABLE(TYPE) \
TYPE(const TYPE&); TYPE& operator=(const TYPE&)
#endif

struct MyStruct
{
...
private:
NONCOPYABLE(MyStruct);
};

关于c++ - std::vector::push_back 不可复制对象给出编译器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13800858/

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