微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

Live code example

我试图在向量中保留指向基类模板化版本的指针的变体。指针的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::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();

如何进行设置,以使内存所有权位于容器中?

解决方法

两件事:

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

第二,虽然链AgeGetter*Getter<int>*std::unique_ptr<Getter<int>>Category的每个转换都是隐式的,但是C ++仅执行有限数量的隐式转换。因此,基本上,此链太长了,您可以例如通过使用emplace_back(std::make_unique<G>())而不是emplace_back(new G())来修复它。

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。