2 Replies - 9404 Views - Last Post: 28 June 2012 - 03:57 PM Rate Topic: -----

#1 vividexstance  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 660
  • View blog
  • Posts: 2,270
  • Joined: 31-December 10

C++11: unique_ptr

Posted 27 June 2012 - 08:08 AM

Here's another drdobbs article on the C++11 feature: unique_ptr.

I was just messing around with unique_ptrs and vectors and it seemed like the author of the article is incorrect about one of the things he said:

Quote

This seems reasonable, but doing this gets me into a gray area: Who owns the pointer? Will the container destroy it at some point in its lifetime? Or is it still my job do so?

The rules of using unique_ptr prohibit this kind of code, and trying to compile it will lead to the classic cascade of template-based compiler errors

But I just compiled and ran this code fine with no warnings or errors:
// UniquePtr.cpp
// Example usage of the C++11 feature: std::unique_ptr.
#include <iostream>
#include <memory>
#include <vector>

using namespace std;

// Test class to log what unique_ptr is actually doing.
class Trace
{
	// Trace object count.
	static size_t count;
	
	// Object id number.
	size_t id;

public:
	Trace() : id(++count) { cout << "Creating Trace object " << id << endl; }
	
	Trace(const Trace& t) : id(++count)
	{
		cout << "Creating Trace object " << id << " as a copy of Trace object " << t.id << endl;
	}
	
	~Trace() { cout << "Destroying Trace object " << id << endl; --count; }
	
	static size_t getCount() { return count; }
	
	friend ostream& operator<<(ostream& out, const Trace& t)
	{
		return out << "Trace object " << t.id;
	}
};

size_t Trace::count = 0;

int main()
{
	{
		const size_t MAX = 10;
		vector<unique_ptr<Trace>> v;
		
		for(size_t i = 0; i < MAX; ++i)
			v.push_back(unique_ptr<Trace>(new Trace));
		
		for(size_t i = 0; i < MAX; ++i)
			cout << "v[" << i << "] = " << *(v[i]) << endl;
	}
}

Compile command line:

Quote

g++ -Wall -ansi -std=c++0x UniquePtr.cpp -o UniquePtr

And here's the output:

Quote

./UniquePtr
Creating Trace object 1
Creating Trace object 2
Creating Trace object 3
Creating Trace object 4
Creating Trace object 5
Creating Trace object 6
Creating Trace object 7
Creating Trace object 8
Creating Trace object 9
Creating Trace object 10
v[0] = Trace object 1
v[1] = Trace object 2
v[2] = Trace object 3
v[3] = Trace object 4
v[4] = Trace object 5
v[5] = Trace object 6
v[6] = Trace object 7
v[7] = Trace object 8
v[8] = Trace object 9
v[9] = Trace object 10
Destroying Trace object 1
Destroying Trace object 2
Destroying Trace object 3
Destroying Trace object 4
Destroying Trace object 5
Destroying Trace object 6
Destroying Trace object 7
Destroying Trace object 8
Destroying Trace object 9
Destroying Trace object 10


I'm not sure if he's talking about something slightly different. In the article his simple example is just:
std::unique_ptr<foo> q( new foo(42) );
v.push_back( q );

I don't see there being much difference in first saving the dynamically allocated memory in a unique_ptr object and then pushing that onto the vector, or doing it the way I did in the code above.

This post has been edited by vividexstance: 27 June 2012 - 11:27 AM


Is This A Good Question/Topic? 0
  • +

Replies To: C++11: unique_ptr

#2 ishkabible  Icon User is offline

  • spelling expret
  • member icon




Reputation: 1622
  • View blog
  • Posts: 5,709
  • Joined: 03-August 09

Re: C++11: unique_ptr

Posted 28 June 2012 - 01:37 PM

wrong:
std::unique_ptr<foo> q( new foo(42) );
v.push_back( q );



this is wrong becuase the pointer wouldn't be unique anymore as it uses the copy constructor. there would a reference the the same pointer in both an element of 'v' and in the variable 'q'; that's not unique however. unique pointers don't have a unique owner but rather a unique reference. the copy constructor dosn't make sense here so it's declared like so unique_ptr(const unique_ptr&) = delete;

the first snippet is perfectly correct becuase it uses the move constructor not the copy constructor. the constructor used in an expression like that creates an rvalue and so the move constructor can be used. the move constructor guarantees that there will only be 1 reference becuase the original reference is destroyed(well, you can't use it at least)

unique_ptr has the exact same overhead has a normal pointer but it's allows for exception safe deallocation. there is no bool to say weather or not that instances owns the pointer or not as some people seem to suspect(you would use a weak pointer for that).

you could force the use of the move constructor however. like so...

ok:
std::unique_ptr<foo> q( new foo(42) );
v.push_back(std::move(q));



however the following is better.

better:
v.push_back(unique_ptr<Trace>{new Trace});


or even better still is to use emplace_back which calls the constructor for you using perfect forwarding
v.emplace_back(new Trace);



edit:
also, I don't thin you would get a cascade of template errors; you should just get something telling you that the copy constructor was 'deleted' or not defined.

This post has been edited by ishkabible: 28 June 2012 - 01:51 PM

Was This Post Helpful? 2
  • +
  • -

#3 vividexstance  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 660
  • View blog
  • Posts: 2,270
  • Joined: 31-December 10

Re: C++11: unique_ptr

Posted 28 June 2012 - 03:57 PM

I figured there was a slight difference between what I was doing and what the article was. Now I see why, after making a few changes. The error was still a lot longer than it really needs to be but you can still see fairly easily what the error is about.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1