Making class with vector<unique_ptr> copy-able

Hello,

I've got a class with a member of type std::vector<std::unique_ptr<MyClass>> and I need it to be fully copy-able.

I don't know how to implement a copy- (and move- if necessary) constructor correctly.

Can someone help me base on this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class A {

private:
    int x;

public:
    A() :
        x(0)
    {

    }
    ~A() {

    }
};

class B {

private:
    std::vector<std::unique_ptr<A>> vec;

public:
    B() :
        vec(std::vector<std::unique_ptr<A>>())
    {
        std::unique_ptr<A> a(new A());
        vec.push_back(std::move(a));
    }
    ~B() {

    }
    // needs to be copy-able!

};


Thanks!

EDIT: I think its important to say that the ownership of all pointers is supposed to get transfered to the newly created object.
Last edited on
> I've got a class with a member of type
> std::vector<std::unique_ptr<MyClass>> and I need it to be fully copy-able.

If you want the objects to be shared, use std::shared_ptr<> instead of std::unique_ptr<>. And use the defaulted copy/move operations and destructor.

Otherwise do a deep copy of the objects for copy / copy assignment, and use the defaulted move / move assignment and destructor.
Could you implement a deep copy / copy assignment for the example above or link me a example ... I'm very new to this and don't want to mess things up by doing un/miss informed stuff.

Thank you very much
> Could you implement a deep copy / copy assignment for the example above or link me a example

Is the class in question (A) a polymorphic type (ie. has virtual functions, and is designed to be inherited from)?
Last edited on
No its not. No virtual functions at all.
> EDIT: I think its important to say that the ownership of all pointers is
> supposed to get transfered to the newly created object.

Hadn't seen this edit. Is that what you really want?

ie no new copies of the objects of type A are to be created?
Last edited on
Yes. I think farther down the road I will use shared_ptr, but for now I need to use unique_ptr.

I tried to created a new vector and std::move the unique_ptrs in the copy-ctor but that doesn't compile.
Last edited on
So don't do anything: by default B is not Copyable or Assignable, but B is Moveable and MoveAssignable.

And when it is moved, the ownership is transferred. Which is what you want.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <vector>
#include <memory>
#include <utility>
#include <algorithm>

struct A
{
    // ...
};

struct B
{
    B() { seq.emplace_back(new A) ; seq.emplace_back(new A) ; }
    // ...

    std::vector< std::unique_ptr<A> > seq ;
};

int main()
{
    B b1 ;

    // B b2 = b1 ; // *** error: copy constructor is deleted

    B b3 = std::move(b1) ; // fine: move constructor

    B b4 ;

    // b4 = b3 ; // *** error: copy assignment is deleted

    b4 = std::move(b3) ; // fine: move assignment

    B b5 ;

    std::swap( b4, b5 ) ; // fine: Moveable and MoveAssignable
}

> I've got a class with a member of type std::vector<std::unique_ptr<MyClass>>
> and I need it to be fully copy-able.
Then use a copy_ptr instead

> Is the class in question (A) a polymorphic type
>> No its not. No virtual functions at all.
¿why do you want pointers then?

> EDIT: I think its important to say that the ownership of all pointers is supposed to get transfered
Oh, so you do not want a copy, but a transfer
Use transfer_owner_ptr then.
> Is the class in question (A) a polymorphic type
>> No its not. No virtual functions at all.
>>> ¿why do you want pointers then?

There is a bit of history behind this vector of pointers.
http://www.cplusplus.com/forum/beginner/110547/
ne555 wrote:
use a copy_ptr instead
[snip]
Use transfer_owner_ptr


Are you making these up? Or are those part of boost or something?

I've never heard of them before, and google search comes up empty.



Anyway, @ OP... you have 2 choices that I can see. Each do slightly different things, so pick whichever one is closer to what you need:

Option 1) Use shared_ptr instead of unique_ptr

shared_ptr can be copied, which will make your vector copyable (and therefore your class copyable). However each vector will "share" ownership of the pointed to object.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
std::vector<std::shared_ptr<int>>  v;
v.emplace_back( new int(1) );

std::vector<std::shared_ptr<int>>  cpy = v;  // OK

cout << *v[0]; // prints 1
cout << *cpy[0]; // also prints 1

*v[0] = 5;

cout << *v[0]; // prints 5 as you'd expect
cout << *cpy[0]; // ALSO prints 5 because it points to the same int 



This is a shallow copy with shared ownership.


Option 2) Do a deep copy of your unique_ptr vector

This involves iterating over the entire vector and creating a copy of each object in the vector.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
std::vector<std::unique_ptr<int>> v;
std::vector<std::unique_ptr<int>> cpy;

v.emplace_back( new int(1) );

// begin deep copy code:
cpy.reserve( v.size() ); // <- optional bit to improve performance
for(auto& i : v)
    cpy.emplace_back( new int(*i) );


// now that each int has been copied, you have a deep copied vector:

cout << *v[0]; // prints 1
cout << *cpy[0]; // also prints 1

*v[0] = 5;

cout << *v[0]; // prints 5
cout << *cpy[0]; // still prints 1... this time 'cpy' has its own ints 




Note that as others have mentioned, the object copying may not be as simple as line 9 above if the object you're copying is of a different type than the pointer. Having virtual functions doesn't really matter... what matters is whether or not the pointer actually IS the type (ie... you can't point to any derived class.. you must point only to the given class)
Last edited on
I'm making them up
The idea is that instead of writing a copy constructor, assignment operator and destructor you make the elements behave as you wish.
So you only need to code an appropriate wrapper for the members.

When you do a = b; where `a' and `b' are "smart" pointers there are several things that may happen
- both refer to the same object. According to who is responsible of the destruction you may have
-- the last one to live have to kill it ( shared_ptr )
-- there is one owner, if it dies the dangling references are set to null ( weak_ptr I think )

- `a' points to another object, that compares equal to the one that `b' points. A clone if you wish ( copy_ptr )

- `a' is responsible for the destruction, `b' now holds nothing ( transfer_owner_ptr, similar to std::auto_ptr or std::unique_ptr )
Doing
B b = std::move(old.b)
gives me
Error 1 error C2248: 'std::unique_ptr<_Ty>::operator =' : cannot access private member declared in class ...

EDIT: Should be B not A
Last edited on
Topic archived. No new replies allowed.