1

I am using unique_ptr in map values. I need to get those values as a list/vector of raw pointers. So far I have done as follows.

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <map>

class Foo {
  public:
    std::string val;

    Foo(std::string v) : val(v) {
    }
 };

 class Unique {
   public:
     std::map<int, std::unique_ptr<Foo>> unique_map;

     std::vector<Foo*> getFoos() {
       std::vector<Foo*> foos;
       for (auto& it : unique_map) {
         foos.push_back(it.second.get());
       }

       return foos;
     }
 };

 int main() {
   Unique unique;
   Foo* f1 = new Foo("1");
   Foo* f2 = new Foo("2");

   unique.unique_map.emplace(1, f1);
   unique.unique_map.emplace(2, f2);

   std::vector<Foo*> foos = unique.getFoos();

   for (Foo* foo : foos) {
     std::cout << foo->val;
   }

   std::cout<<"\n";

   return 0;
 }

But this fails to compile. The most relevent error message seems to be

"/usr/include/c++/4.8/bits/stl_tree.h:140:49: note: cannot convert ‘std::forward((* & __args#1))’ (type ‘Foo*’) to type ‘const std::unique_ptr&’"

But I am not sure I understand what it means since my understanding is that it.second returns a reference to the unique_ptr not the Foo instance it self assuming that's where the problem is. What needs to be done to fix this example?

Edit I am using a somewhat older g++ version.

g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4

with command line.

g++ -std=c++11 -o unique unique.cpp

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
chamibuddhika
  • 1,419
  • 2
  • 20
  • 36

2 Answers2

1

When I run this code, the complaint seems to be related to the creation of the std::pair class.

unique.unique_map.emplace(1, std::unique_ptr<Foo>(f1));
unique.unique_map.emplace(2, std::unique_ptr<Foo>(f2));

For me, this builds and it works, not that I can say for certain that it will really do what you desire. Just that it compiles and runs for me.

I spend most of my C++ time using QT libraries and classes, but, it looks to me like it is failing to find a way to turn a pair with a FOO* to the unique_ptr<FOO>.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Andrew
  • 816
  • 7
  • 15
  • Indeed! When I used the explicit std::pair based insertion it worked. Looks like emplace doesn't work the way I was thinking (at least for my current compiler it seems). – chamibuddhika Jul 06 '16 at 18:32
1

The error you are getting is because implicit conversion of Foo* to std::unique_ptr<Foo> is not allowed. That is because, the constructor of unique_ptr taking a raw pointer is marked explicit.

explicit
      unique_ptr(pointer __p) noexcept
      : _M_t(__p, deleter_type())
      { static_assert(!is_pointer<deleter_type>::value,
                     "constructed with null function pointer deleter"); }

So, you should be creating a unique_ptr and move it while doing an emplace

NOTE: I am not sure why or how its working in g++ > 6.0 library. But personally I don't think its safe to convert raw pointers to smart pointer implicitly. To know why, see : https://stackoverflow.com/a/11367997/434233

Community
  • 1
  • 1
Arunmu
  • 6,837
  • 1
  • 24
  • 46
  • Thanks for the explanation and the link. Makes more sense now. I am going to accept it as the better answer since you explained the reason for this behavior. – chamibuddhika Jul 06 '16 at 18:50
  • @Arunmu Totally agree that this implicit conversion is dangerous, but the Sutter article you link to talks about the other direction (smart to raw, not raw to smart). – Thomas Jul 06 '16 at 18:56
  • @Thomas Yeah, thanks. Updated the link to point to relevant answer – Arunmu Jul 06 '16 at 19:03