如何在由boost::variant包装的指针容器中将原始指针更改为unique_ptr



实时代码示例

我试图在向量中保存一个指向基类模板化版本的指针变体。指针的boost::variant恰好包含在一个结构中。如果这些指针是原始指针,它可以正常工作,但当我将它们更改为unique_ptr时,事情就开始出错了。

struct Sayer {
struct Category {
using GetterVariant = boost::variant<
//Getter<string>*, // works OK
//Getter<double>*, // ...
//Getter<int>*     // ...
unique_ptr<Getter<string>>,
unique_ptr<Getter<double>>,
unique_ptr<Getter<int>>
>;
Category(GetterVariant g) :
getter(g)
{}
GetterVariant getter;
};
vector<Category> categories;
template <typename G>
void addGetter() {
categories.emplace_back(new G()); // allocate here, transfer ownership to Sayer::categories
}
};

编译器错误:

/usr/include/boost/variant/variant.hpp:1627:28: error: no matching member
function for call to 'initialize'
initializer::initialize(
~~~~~~~~~~~~~^~~~~~~~~~
/usr/include/boost/variant/variant.hpp:1798:9: note: in instantiation of function
template specialization
'boost::variant<std::unique_ptr<Getter<std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> > >,
std::default_delete<Getter<std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> > > > >,
std::unique_ptr<Getter<double>, std::default_delete<Getter<double> > >,
std::unique_ptr<Getter<int>, std::default_delete<Getter<int> > >
>::convert_construct<AgeGetter *>' requested here
convert_construct( detail::variant::move(operand), 1L);
...
main.cpp:54:16: note: in instantiation of function template specialization
'std::vector<Sayer::Category, std::allocator<Sayer::Category>
>::emplace_back<AgeGetter *>' requested here
categories.emplace_back(new G());
^
main.cpp:65:9: note: in instantiation of function template specialization
'Sayer::addGetter<AgeGetter>' requested here
sayer.addGetter<AgeGetter>();
...
/usr/include/boost/variant/detail/initializer.hpp:115:24: note: candidate
function not viable: no known conversion from 'typename
::boost::move_detail::remove_reference<AgeGetter *&>::type'
(aka 'AgeGetter *') to 'std::unique_ptr<Getter<int>,
std::default_delete<Getter<int> > >' for 2nd argument
/usr/include/boost/variant/detail/initializer.hpp:149:17: note: candidate
function not viable: requires 0 arguments, but 2 were provided
static void initialize();

我该如何设置,以便内存所有权在容器中?

两件事:

首先,您必须在Category构造函数中移动g,因为如果变体的任何成员都不可复制,那么它就是不可复制的。

其次,虽然链AgeGetter*Getter<int>*std::unique_ptr<Getter<int>>Category中的每个转换都是隐式的,但C++只进行有限数量的隐式转换。所以基本上这个链太长了,你可以通过使用emplace_back(std::make_unique<G>())而不是emplace_back(new G())来修复它。

此外,这更安全,因为如果emplace_back抛出(它可以(,new G()将不会被删除,从而泄漏。但如果emplace_back抛出,则会调用std::make_unique<G>()返回的析构函数unique_ptr,因此不会发生泄漏。您应该始终尽量避免在代码中使用原始new

最新更新