如何修复具有 unique_ptr 的对象的向量
How to fix vector of objects that have unique_ptr
我有以下代码,其中包含 class 的向量,其中某些成员声明为 unique_ptr。
struct Container
{
struct Nested{
std::unique_ptr<Container> node;
Nested(std::unique_ptr<Container> t) : node(std::move(t)) {}
Nested(const Nested& t) { node = std::move(t.node); };
};
std::vector<Nested> edges;
};
typedef std::unique_ptr<Container> UCont;
typedef Container::Nested Nested;
int main()
{
std::unique_ptr<Container> object = UCont(new Container{{
Nested(UCont(new Container{{}})),
Nested(UCont(new Container{{}})),
Nested(UCont(new Container{{}}))
}});
}
现在编译它会出现以下错误:
..[=12=].UniquePtrVector.cpp: In copy constructor 'Container::Nested::Nested(const Container::Nested&)':
..[=12=].UniquePtrVector.cpp:20:35: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Container; _Dp = std::default_delete<Container>]'
Nested(const Nested& t) { node = std::move(t.node); };
^
In file included from c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\locale_conv.h:41:0,
from c:\mingw\lib\gcc\mingw32.3.0\include\c++\locale:43,
from c:\mingw\lib\gcc\mingw32.3.0\include\c++\iomanip:43,
from c:\mingw\lib\gcc\mingw32.3.0\include\c++\mingw32\bits\stdc++.h:71,
from ..[=12=].UniquePtrVector.cpp:10:
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\unique_ptr.h:357:19: note: declared here
unique_ptr& operator=(const unique_ptr&) = delete;
我不确定如何修复此错误。我想删除复制构造函数也不是一个选项。有帮助吗?
编辑:
更改为
Nested(std::unique_ptr<Container>&& t) : node(std::move(t)) {}
Nested(Nested&& t) : node(std::move(t.node)) {}
Nested(const Nested& t) =delete;
也报错:
In file included from c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_tempbuf.h:60:0,
from c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_algo.h:62,
from c:\mingw\lib\gcc\mingw32.3.0\include\c++\algorithm:62,
from c:\mingw\lib\gcc\mingw32.3.0\include\c++\mingw32\bits\stdc++.h:64,
from ..[=14=].UniquePtrVector.cpp:10:
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = Container::Nested; _Args = {const Container::Nested&}]':
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_uninitialized.h:75:18: required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const Container::Nested*; _ForwardIterator = Container::Nested*; bool _TrivialValueTypes = false]'
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_uninitialized.h:126:15: required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const Container::Nested*; _ForwardIterator = Container::Nested*]'
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_uninitialized.h:281:37: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = const Container::Nested*; _ForwardIterator = Container::Nested*; _Tp = Container::Nested]'
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_vector.h:1290:33: required from 'void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const Container::Nested*; _Tp = Container::Nested; _Alloc = std::allocator<Container::Nested>]'
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_vector.h:377:21: required from 'std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = Container::Nested; _Alloc = std::allocator<Container::Nested>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<Container::Nested>]'
..[=14=].UniquePtrVector.cpp:36:11: required from here
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_construct.h:75:7: error: use of deleted function 'Container::Nested::Nested(const Container::Nested&)'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^
..[=14=].UniquePtrVector.cpp:20:11: note: declared here
Nested(const Nested& t) =delete;
^
当您在复制构造函数中移动 t.node
时,t.node
需要更改。但是 t
是常量,所以移动是无效的。 unique_ptr
不能复制构造,因此 struct Nested
也不能复制构造。
要使其正常工作,您需要提供移动构造函数并删除复制构造函数。像这样:
struct Nested{
std::unique_ptr<Container> node;
Nested(std::unique_ptr<Container>&& t) : node(std::move(t)) {}
Nested(Nested&& t) : node(std::move(t.node)) {}
Nested(const Nested& t) =delete;
};
tl;dr :考虑使用 rule of zero
我会谨慎地在您的 class 中明确指定所有这些构造函数。 unique_ptr 无法复制这一事实会让您在按照您尝试的方式做事时遇到各种麻烦。相反,当您不指定 any 构造函数时会发生以下情况:
#include <vector>
#include <memory>
struct Container
{
struct Nested{
std::unique_ptr<Container> node;
//
// Nested(std::unique_ptr<Container> t) : node(std::move(t)) {}
// Nested(const Nested& t) { node = std::move(t.node); };
};
std::vector<Nested> edges;
};
typedef std::unique_ptr<Container> UCont;
typedef Container::Nested Nested;
int main()
{
auto c1 = new Container{};
auto c2 = new Container{};
auto c3 = new Container{};
std::unique_ptr<Container> u1 {c1};
std::unique_ptr<Container> u2 {c2};
std::unique_ptr<Container> u3 {c3};
Nested n1 {std::move(u1)};
Nested n2 {std::move(u2)};
Nested n3 {std::move(u3)};
auto v = std::vector<Nested>{3};
v.push_back(std::move(n1));
v.push_back(std::move(n2));
v.push_back(std::move(n3));
auto c5 = new Container { std::move(v) };
std::unique_ptr<Container> object = UCont(std::move(c5));
}
为了清楚起见,我已将所有内容分解为较短的陈述(大部分)。
我收到错误的根本原因是在初始化列表中使用的对象中使用了 unique_ptr
。类似于简单 unique_ptr
的向量(如此处 Initializing container of unique_ptrs from initializer list fails with GCC 4.7 ),在其数据模型中也具有 unique_ptr
的对象也不能在初始化列表中使用。
与另一个link相似,原因相同; initializer list 始终执行复制,并且 unique_ptr
无法复制。所以我们要用emplace_back
/push_back
.
因此,即使使用构造函数,以下解决方案也有效
struct Container
{
struct Nested{
std::unique_ptr<Container> node;
Nested(): node(nullptr) {}
Nested(std::unique_ptr<Container> t) : node(std::move(t)) {}
};
std::vector<Nested> edges;
};
typedef std::unique_ptr<Container> UCont;
typedef Container::Nested Nested;
int main()
{
auto v = std::vector<Nested>{3};
v.push_back(std::move(Nested(std::move(std::unique_ptr<Container>(new Container{})))));
v.push_back(std::move(Nested(std::move(std::unique_ptr<Container>(new Container{})))));
v.push_back(std::move(Nested(std::move(std::unique_ptr<Container>(new Container{})))));
std::unique_ptr<Container> object = UCont(new Container { std::move(v) });
}
我有以下代码,其中包含 class 的向量,其中某些成员声明为 unique_ptr。
struct Container
{
struct Nested{
std::unique_ptr<Container> node;
Nested(std::unique_ptr<Container> t) : node(std::move(t)) {}
Nested(const Nested& t) { node = std::move(t.node); };
};
std::vector<Nested> edges;
};
typedef std::unique_ptr<Container> UCont;
typedef Container::Nested Nested;
int main()
{
std::unique_ptr<Container> object = UCont(new Container{{
Nested(UCont(new Container{{}})),
Nested(UCont(new Container{{}})),
Nested(UCont(new Container{{}}))
}});
}
现在编译它会出现以下错误:
..[=12=].UniquePtrVector.cpp: In copy constructor 'Container::Nested::Nested(const Container::Nested&)':
..[=12=].UniquePtrVector.cpp:20:35: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Container; _Dp = std::default_delete<Container>]'
Nested(const Nested& t) { node = std::move(t.node); };
^
In file included from c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\locale_conv.h:41:0,
from c:\mingw\lib\gcc\mingw32.3.0\include\c++\locale:43,
from c:\mingw\lib\gcc\mingw32.3.0\include\c++\iomanip:43,
from c:\mingw\lib\gcc\mingw32.3.0\include\c++\mingw32\bits\stdc++.h:71,
from ..[=12=].UniquePtrVector.cpp:10:
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\unique_ptr.h:357:19: note: declared here
unique_ptr& operator=(const unique_ptr&) = delete;
我不确定如何修复此错误。我想删除复制构造函数也不是一个选项。有帮助吗?
编辑: 更改为
Nested(std::unique_ptr<Container>&& t) : node(std::move(t)) {}
Nested(Nested&& t) : node(std::move(t.node)) {}
Nested(const Nested& t) =delete;
也报错:
In file included from c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_tempbuf.h:60:0,
from c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_algo.h:62,
from c:\mingw\lib\gcc\mingw32.3.0\include\c++\algorithm:62,
from c:\mingw\lib\gcc\mingw32.3.0\include\c++\mingw32\bits\stdc++.h:64,
from ..[=14=].UniquePtrVector.cpp:10:
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = Container::Nested; _Args = {const Container::Nested&}]':
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_uninitialized.h:75:18: required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const Container::Nested*; _ForwardIterator = Container::Nested*; bool _TrivialValueTypes = false]'
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_uninitialized.h:126:15: required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const Container::Nested*; _ForwardIterator = Container::Nested*]'
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_uninitialized.h:281:37: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = const Container::Nested*; _ForwardIterator = Container::Nested*; _Tp = Container::Nested]'
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_vector.h:1290:33: required from 'void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const Container::Nested*; _Tp = Container::Nested; _Alloc = std::allocator<Container::Nested>]'
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_vector.h:377:21: required from 'std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = Container::Nested; _Alloc = std::allocator<Container::Nested>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<Container::Nested>]'
..[=14=].UniquePtrVector.cpp:36:11: required from here
c:\mingw\lib\gcc\mingw32.3.0\include\c++\bits\stl_construct.h:75:7: error: use of deleted function 'Container::Nested::Nested(const Container::Nested&)'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^
..[=14=].UniquePtrVector.cpp:20:11: note: declared here
Nested(const Nested& t) =delete;
^
当您在复制构造函数中移动 t.node
时,t.node
需要更改。但是 t
是常量,所以移动是无效的。 unique_ptr
不能复制构造,因此 struct Nested
也不能复制构造。
要使其正常工作,您需要提供移动构造函数并删除复制构造函数。像这样:
struct Nested{
std::unique_ptr<Container> node;
Nested(std::unique_ptr<Container>&& t) : node(std::move(t)) {}
Nested(Nested&& t) : node(std::move(t.node)) {}
Nested(const Nested& t) =delete;
};
tl;dr :考虑使用 rule of zero
我会谨慎地在您的 class 中明确指定所有这些构造函数。 unique_ptr 无法复制这一事实会让您在按照您尝试的方式做事时遇到各种麻烦。相反,当您不指定 any 构造函数时会发生以下情况:
#include <vector>
#include <memory>
struct Container
{
struct Nested{
std::unique_ptr<Container> node;
//
// Nested(std::unique_ptr<Container> t) : node(std::move(t)) {}
// Nested(const Nested& t) { node = std::move(t.node); };
};
std::vector<Nested> edges;
};
typedef std::unique_ptr<Container> UCont;
typedef Container::Nested Nested;
int main()
{
auto c1 = new Container{};
auto c2 = new Container{};
auto c3 = new Container{};
std::unique_ptr<Container> u1 {c1};
std::unique_ptr<Container> u2 {c2};
std::unique_ptr<Container> u3 {c3};
Nested n1 {std::move(u1)};
Nested n2 {std::move(u2)};
Nested n3 {std::move(u3)};
auto v = std::vector<Nested>{3};
v.push_back(std::move(n1));
v.push_back(std::move(n2));
v.push_back(std::move(n3));
auto c5 = new Container { std::move(v) };
std::unique_ptr<Container> object = UCont(std::move(c5));
}
为了清楚起见,我已将所有内容分解为较短的陈述(大部分)。
我收到错误的根本原因是在初始化列表中使用的对象中使用了 unique_ptr
。类似于简单 unique_ptr
的向量(如此处 Initializing container of unique_ptrs from initializer list fails with GCC 4.7 ),在其数据模型中也具有 unique_ptr
的对象也不能在初始化列表中使用。
与另一个link相似,原因相同; initializer list 始终执行复制,并且 unique_ptr
无法复制。所以我们要用emplace_back
/push_back
.
因此,即使使用构造函数,以下解决方案也有效
struct Container
{
struct Nested{
std::unique_ptr<Container> node;
Nested(): node(nullptr) {}
Nested(std::unique_ptr<Container> t) : node(std::move(t)) {}
};
std::vector<Nested> edges;
};
typedef std::unique_ptr<Container> UCont;
typedef Container::Nested Nested;
int main()
{
auto v = std::vector<Nested>{3};
v.push_back(std::move(Nested(std::move(std::unique_ptr<Container>(new Container{})))));
v.push_back(std::move(Nested(std::move(std::unique_ptr<Container>(new Container{})))));
v.push_back(std::move(Nested(std::move(std::unique_ptr<Container>(new Container{})))));
std::unique_ptr<Container> object = UCont(new Container { std::move(v) });
}