C++x0 unique_ptr GCC 4.4.4 - c++

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?

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.

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.

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

Related

why does insert in std::unordered_set call the copy constructor?

I have an std::unordered_set of pointers. If I do
int main()
{
std::unordered_set<std::unique_ptr<int>> set;
set.insert(std::make_unique(3));
}
everything works and insert calls the move constructor (i think). However I have a different situation that is similar to the following code
std::unordered_set<std::unique_ptr<int>> set;
void add(const std::unique_ptr<int>& obj) {set.insert(obj);}
int main
{
std::unique_ptr<int> val = std::make_unique<int>(3);
add(std::move(val));
}
and this does not compile. It gives
State Error C2280 'std::unique_ptr<int,std::default_delete>::unique_ptr(const std::unique_ptr<int,std::default_delete> &)': attempting to reference a deleted function
which means that it's trying to call the copy constructor (right?). So the question is: why insert doesn't move the object when it is inside a function? I tried also passing the pointer to the unique_ptr and even adding std::move pretty much everywhere but the copy constructor is always called
void add(const std::unique_ptr<int>& obj)
It comes down to something fundamental: you cannot move a constant object, by definition. "Move" basically means ripping the guts out of the moved-from object, and shoving all the guts into the new, moved-to object (in the most efficient manner possible, with the precision of a surgeon). And you can't do it if the moved-from object is const. It's untouchable. It must remain in its original, pristine condition.
You should be able to do that if the parameter is an rvalue reference:
void add(std::unique_ptr<int>&& obj) {set.insert(std::move(obj));}
std::unique_ptr by definition does not have a copy constructor. It does have a move constructor. But your unique pointer here is a const, so the move constructor cannot be called

Returning unique_ptr variable returns an error

I came across a weird problem. I get an error message in setGetDog() method when written this way:
class Dog
{
public:
void bark() { std::cout << "Bark!" << std::endl; }
};
class test
{
public:
std::unique_ptr<Dog> setGetDog()
{
if (!dog_)
{
dog_ = std::make_unique<Dog>();
}
return dog_;
}
private:
std::unique_ptr<Dog> dog_;
};
int main()
{
auto testClass = std::make_unique<test>();
auto dog = testClass->setGetDog();
}
Error is like this:
error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Dog; _Dp = std::default_delete<Dog>]'
But when I change the implementation to:
std::unique_ptr<Dog> setGetDog()
{
return std::make_unique<Dog>();
}
It works just fine.
What is the matter with dog_?
I do not understand why the error states that it is deleted when in fact test is still alive when the method was called (and so dog_ as well).
I know I can write this some other way but I'm specifically curious on why behavior is like this on this implementation.
Can anyone please enlighten me?
There are a few different types of value categories/situations that objects have that affects how there are returned from a function. Lets look at the rvalue category first. When you do
std::unique_ptr<Dog> setGetDog()
{
return std::make_unique<Dog>();
}
std::make_unique<Dog>() returns by value making the return object an rvalue. That means that when the compiler returns the object it will implicitly move it. (the compiler can also elide the copy but that doesn't matter for this discussion) Since the object is moved you don't have any issues since std::unique_ptr is movable.
The second case is when you have an lvalue, but it is a function local object. If you had
std::unique_ptr<Dog> setGetDog()
{
auto ptr = std::make_unique<Dog>();
return ptr;
}
Here ptr is an lvalue but it is going away so we can call it an xvalue(expiring value). With xvalues, when you return them the compiler tries to move it, since moving it is a safe operation in this case. If the move operation does not exist/is not viable, then the compiler falls back to copying. Since std::unique_ptr is movable, it gets moved without error.
The last case is when you have a plain lvalue like you have with
class test
{
public:
std::unique_ptr<Dog> setGetDog()
{
if (!dog_)
{
dog_ = std::make_unique<Dog>();
}
return dog_;
}
private:
std::unique_ptr<Dog> dog_;
};
Here, dog_ is a member of the class, not a object local to the function. This means the only thing the compiler can do is try and make a copy. Since you can't copy a unique_ptr, you get an error. You would need return std::move(dog_); for it to compile, but if you did that dog_ in the class would be empty.
When you just return the unique_ptr then return value optimization can be applied. This is because the unique_ptr can actually be constructed at the address of the unique_ptr instance in the calling function. The compiler allows this as no copying is occurring.
When you add the if, the function may or may not be trying to return an existing instance. It's a runtime decision. An existing instance wont have the opportunity to be constructed where the calling function wants it and so must be copied.
unique_ptr has a deleted copy constructor to preserve the unique part of its contract, so the code does not compile.
Depending on your needs you may want to use a shared_ptr, use std::move (mistake probably, it empties the unique_ptr inside your class) or use value semantics to copy the actual object and not the pointer to it.

Lazy initialization of std::unique_ptr

I have a class with std::unique_ptr members which are initially initialized to nullptr and later assigned an actual object. They also use custom deleters.
I have two questions regarding this scenario: Should I use std::unique_ptr::reset() or copy assignment operator to assign a value to a unique pointer which was first initialized to nullptr? And if the latter is the case, then how can I make the code below work?
class MyClass {
private:
std::unique_ptr<Foo, void(*)(Foo*)> m_foo;
std::unique_ptr<Bar, void(*)(Bar*)> m_bar;
}
MyClass::MyClass() : m_foo(nullptr, ReleaseFoo), m_bar(nullptr, ReleaseBar) { }
bool MyClass::init()
{
m_foo.reset(CreateFoo()); // works ok
m_bar = std::unique_ptr<Bar, ReleaseBar>(CreateBar()); // 'ReleaseBar' is not a valid template type argument for parameter '_Dx'
}
Also, would the answer change if no custom deleters were involved (i.e. use reset with custom deleters and copy assignment otherwise)?
You can use resetor the move assignment operator to assign a new value.
The problem with your statement
m_bar = std::unique_ptr<Bar, ReleaseBar>(CreateBar()); // 'ReleaseBar' is not a valid template type argument for parameter '_Dx'
is, as the error message you quote indicates, that ReleaseBar is not a valid template argument. Earlier code uses ReleaseBar in a way consistent with this being a function name. In the earlier code the corresponding template argument was void(*)(Bar*).

Why do I get this error when I add another constructor?

I will gladly change the title of this thread to something more appropriate once I know what subject this falls under.
If I change the parameters of the error-causing constructor, there is no error.
This error only occurs if I include that exact constructor:
error: no matching function for call to 'Object::Object(Object)'
note: candidates are: Object::Object(Object&)
note: Object::Object()
Code:
#include <iostream>
using namespace std;
class Object {
public:
Object() {} /* default constructor - no problems at all */
Object( Object & toCopy ) {} /* Cause of error, but no error when commented out */
Object func() {
Object obj;
return obj;
}
};
int main() {
Object o = o.func(); /* this is the line that the error is actually on */
return 0;
}
You have declared an unusual and terrible copy constructor, namely one which takes the argument by non-constant reference. This is possible, and it means that no other copy constructor will be defined implicitly. However, it also means that you cannot construct copies from temporary values, since those don't bind to non-constant references.
Unless you had a reason to do what you were doing (maybe you want to define auto_obj :-) ?), you should declare the usual copy constructor with argument Object const & (but make sure to define it correctly!), or just leave it out entirely and rely on the implicitly generated version (as happens when you "comment out the line" in your code); or in C++11 you can default the copy constructor by declaring Object(Object const &) = default;.
(Note that the popular Rule of Three says that you either should not be defining your own, non-trivial copy constructor, or if you do, then you also need a user-defined destructor and assignment operator. Make sure your code is sane.)
the error you got
error: no matching function for call to 'Object::Object(Object)'
note: candidates are: Object::Object(Object&)
note: Object::Object()
means that compiler is looking for appropriate copy constructor for class Object. There is no such function in your class definition: your version cannot be used to bind temporary (see below). The correct version might be defined by yourself with:
Object(const Object& orig) {
// and initialize data here, and return
}
or you can just don't declare such function, and working version will be generated automatically, thus there is no error then as well.
note:
you are trying to define Object( Object & toCopy ) {}. This is not correct because taking non-const reference to temporary means you cannot use this temporary object to create a copy from it in your constructor because temporary objects cannot be assigned to non-const reference.
So to express this diferent way:
-> compiler is searching for copy constructor
-> finds your version
-> and this version tells: I will not do it
Finally:
Object o = o.func();
this is not good idea. Referring to nonstatic members of objects that have not been constructed or have already been destructed is undefined behavior. Make func() static so might be used like Object::func() or call it on properly constructed object.
Try Object(const Object &toCopy) { }
As already pointed out by many previously, the problem is that you only defined a copy constructor taking a reference, but the return of the call of o.func(); is an rvalue, which can only bind to rvalue references or const references, not to regular references.
Your code however has another issue, calling func() on o, which at that point is a yet uninitialized object, is a very bad idea. Maybe you intended to implement the factory idiom? In this case I would advise that you declare Object func(); static, and call it from the scope of Object, like so:
Object o = Object::func();

compile error in template member conversion operator

I'm trying to write a conversion operator function template in a class and running into some compile errors which I don't fully understand.
class ABC { };
class BBC:public ABC { };
template <class T>
class TestPtr
{
public:
TestPtr(T* ptr=0)
: _pointee(ptr)
{ }
TestPtr(TestPtr& rhs)
{
this->_pointee = rhs._pointee;
rhs._pointee= 0;
}
template <class U> operator TestPtr<U>();
private:
T* _pointee;
};
template <class T> template <class U>
TestPtr<T>::operator TestPtr<U>()
{
return TestPtr<U>(this->_pointee); // if this line is changed to
//TestPtr<U> x(this->_pointee); // these commented lines, the
//return x; // compiler is happy
}
void foo (const TestPtr<ABC>& pmp)
{ }
int main() {
TestPtr<BBC> tbc(new BBC());
foo(tbc);
}
The above code results in the following errors
TestPtr.cpp: In member function ‘TestPtr<T>::operator TestPtr<U>() [with U = ABC, T = BBC]’:
TestPtr.cpp:38:9: instantiated from here
TestPtr.cpp:28:34: error: no matching function for call to ‘TestPtr<ABC>::TestPtr(TestPtr<ABC>)’
TestPtr.cpp:28:34: note: candidates are:
TestPtr.cpp:13:3: note: TestPtr<T>::TestPtr(TestPtr<T>&) [with T = ABC, TestPtr<T> = TestPtr<ABC>]
TestPtr.cpp:13:3: note: no known conversion for argument 1 from ‘TestPtr<ABC>’ to ‘TestPtr<ABC>&’
TestPtr.cpp:9:3: note: TestPtr<T>::TestPtr(T*) [with T = ABC]
TestPtr.cpp:9:3: note: no known conversion for argument 1 from ‘TestPtr<ABC>’ to ‘ABC*’
Now what is baffling to me is that the compiler is trying to pick TestPtr<ABC>::TestPtr(TestPtr<ABC>) instead of TestPtr<ABC>::TestPtr(ABC *) in the return statement. However if I create a variable with the intended constructor first and then return the value it works fine. I also made the T* constructor explicit with no avail.
I've tried with both g++ and clang++ with similar results. Can someone please explain what's going on here?
The problem is with your copy constructor. Its parameter is a TestPtr& (a non-const reference):
TestPtr(TestPtr& rhs)
A non-const reference cannot bind to an rvalue expression. TestPtr<U>(this->_pointee) is an rvalue expression that creates a temporary object. When you try to return this object directly, a copy must be made. Thus, you get this error when the compiler is unable to call the copy constructor.
Usually the solution would be to have your copy constructor take a const reference. However, in this case, the solution is a bit trickier; you'll want to do something similar to what std::auto_ptr does. I described its dirty tricks in an answer to "How could one implement std::auto_ptr's copy constructor?"
Alternatively, if you are using a recent C++ compiler and only need to support compilers that support rvalue references, you can make your class movable but noncopyable by providing an user-declared move constructor (TestPtr(TestPtr&&)) and by suppressing the copy constructor (declaring it =delete if your compiler supports deleted member functions, or declaring it private and not defining it).
Note also that you must provide a user-declared copy assignment operator. (Or, if you decide to make the type move-only, you'll need to provide a user-declared move assignment operator and suppress the implicit copy assignment operator, again using = delete or by declaring and not defining it.)
In your copy constructor you for some reason insist on zeroing-out the source pointer
TestPtr(TestPtr& rhs)
{
this->_pointee = rhs._pointee;
rhs._pointee= 0;
}
Why are you doing this?
Since you insist on zeroing-out rhs, you cannot declare the argument as const TestPtr& rhs, which in turn breaks your code, as James explained.
I don't see any reason to zero-out the source pointer. Just do
TestPtr(const TestPtr& rhs) : _pointee(rhs._pointee)
{}
and it should work.
I suspect that you used std::auto_ptr for inspiration and saw something like that in its copying routines. However, in std::auto_ptr the source pointer is zeroed-out because std::auto_ptr takes ownership of the object it points to and transfers that ownership when it gets copied. The need for the ownership management is dictated by the fact that std::auto_ptr not only points to objects, it also attempts to destroy them automatically.
Your pointer does not attempt to destroy anything. It doesn't need to take ownership of the pointed object. For this reason you don't need to zero-out the source when you copy your pointer.