tags:

views:

195

answers:

3

Hi,

I am trying to make use of the unique_ptr from C++x0, by doing

#include <memory> 

and comping with -std=c++0x, however it is throwing up many errors this being an example.

/usr/lib/gcc/x86_64-redhat-linux/4.4.4/../../../../include/c++/4.4.4/bits/unique_ptr.h:214: error: deleted function ‘std::unique_ptr<_Tp, _Tp_Deleter>::unique_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = Descriptor, _Tp_Deleter = std::default_delete<Descriptor>]’

UPDATE** This is what I am trying to do, I have removed typedefs so you can see clearly the types

static std::unique_ptr<SomeType> GetSomeType()
{
    std::unique_ptr<SomeType> st("Data","Data2",false);

    std::unique_ptr<OtherType> ot("uniportantconstructor data");

    st->Add(ot);

    return st;

}

//Public method of SomeType
  void Add(std::unique_ptr<OtherType> ot)
  {
    //otmap is std::map<std::string,std::unique_ptr<OtherType> >
    //mappair is std::Pair<std::string,std::unique_ptr<OtherType> >
     otMap.Insert(mappair(ot->name(),ot)); 
  }

UPDATE:

If my class SomeType has a method that returns a element from the map (using the key) say

std::unique_ptr<OtherType> get_othertype(std::string name)
{
   return otMap.find(name);
}

that would enure the caller would recieve a pointer to the one in the map rather than a copy?

+4  A: 

It looks like you're trying to use the copy constructor. There isn't one. If your calling code looks like this:

T *ptr = /* whatever */;
std::unique_ptr<T> up = ptr;

You have to change the second line to this:

std::unique_ptr<T> up (ptr);

The original version is (basically) implicitly turning the assignment into:

std::unique_ptr<T> up (std::unique_ptr<T>(ptr));

The copy constructor has been deleted. "deleted function" is C++0x-speak for explicitly removing an implicit special member function. In this case, the copy constructor.

Steve M
Thanks, and that explanation of the error should help in the future.
Mark
Does this mean I cant pass unique_ptr as a parameter or return it from a function?
Mark
@Mark: No, to both. But you have to do so using the move constructor, rather than the copy constructor. For instance, `function(std::move(pointer));`
Dennis Zickefoose
I am surprised that gcc didn't invoke the move constructor instead of the copy constructor in this case. Could it be a bug or just not implemented yet?
Steve M
Still getting error, going back to boost::shared_ptr.
Mark
I was just guessing about your code; how about posting a snippet?
Steve M
Seems overly complex, I have went back to shared_ptr, much easier.
Mark
@Mark: They just have completely different meaning. `unique_ptr` means that the object will not be shared with other pointers. Where transfer of ownership is implicit with `auto_ptr`, you have to be explicit with `unique_ptr`, except where rules concerning rvalue references kick in (such as returning a local `unique_ptr` by value).
UncleBens
The problem here is not a nonexisting copy constructor but simply that the constructor that takes a pointer is `explicit`. `explicit` constructors are basically ignored in the copy initialization syntax. Note that "copy initialization" doesn't imply copying but may involve a move construction. Your first and third example will compile if you make the constructor taking a ptr implicit.
sellibitze
See my update with code example of what I am trying to achieve, Thanks for the input so far though, appreciated
Mark
+1  A: 

As @Steve said you're probably using the copy constructor, unique_ptr does not support copy semantics, if you want to move to value to another unique_ptr you're have to move it.

 unique_ptr<T> other = std::move(orig); // orig is now null
Motti
+2  A: 
std::unique_ptr<OtherType> ot("unimportant constructor data");
st->Add(ot);

You cannot pass an lvalue to a function accepting a unique_pointer, because unique_pointer has no copy constructor. You must either move the lvalue (to cast it to an xvalue) or pass a prvalue:

// pass an xvalue:
std::unique_ptr<OtherType> ot("unimportant constructor data");
st->Add(std::move(ot));
// note: ot is now empty

// pass a prvalue:
st->Add(std::unique_ptr<OtherType>("unimportant constructor data"));

Inside the Add method, things are a little more complicated. First, you have to move from ot, because formal parameters are always lvalues (since they have names). Second, you cannot move from ot and get ot->name() as arguments to the mappair function, because the order of argument evaluation is unspecified in C++. So we have to get ot->name() in a separate statement before moving from ot:

void Add(std::unique_ptr<OtherType> ot)
{
    auto name = ot->name();
    otMap.Insert(mappair(name, std::move(ot))); 
}

Hope this helps. Note that under no (sane) circumstances can two unique_ptr objects point to the same thing. If you need that functionality, unique_ptr is not what you want.

FredOverflow
Awesome that is exactly what I was looking for, thank you.
Mark
don't forget to include `<utility>` to get `std::move`
sellibitze