How to declare a vector of unique_ptr's as class data member?
Asked Answered
N

6

13

I'd like to have a vector of unique_ptr's as a member of a class I'm making.

class Foo {
    [...]

private:
    vector<unique_ptr<Bar>> barList;
}

But then I start getting cryptic error messages from the VS2010 compiler:

error C2248: 'std::unique_ptr<_Ty>::operator =' : cannot access private member declared in class 'std::unique_ptr<_Ty>'

Along with a handful of error lines below that which dive into Microsoft's implementation of std::_Copy_impl<>...

I changed the member declaration to

vector<unique_ptr<Bar>>* barList;

And it compiles. But I can't help but wonder why I can't do it the way I originally wanted? For grins, I tried this and it works fine:

vector<Bar> barList;

But now I lose the convenience of unique_ptr. I want my cake and I want to eat it too!

Ningsia answered 24/1, 2012 at 14:15 Comment(3)
I was looking at https://mcmap.net/q/429659/-vector-as-a-class-member and the answer seems to think declaring a vector like I did is just fine to do. For some reason, though, it seems to trigger illegal copies when adding the unique_ptr part.Ningsia
What do your copy constructor and assignment operator look like?Property
Private assignment, but copy constructor was the culprit. Switched from unique_ptr to shared_ptr when I realized I was using the wrong ownership semantic.Ningsia
I
12

The problem here is that somewhere, your code is attempting to call the "copy-assignment" operator of Foo.

This causes the compiler to attempt to generate a copy-assignment operator which calls the copy-assignment operators of all the subobjects of Foo. Eventually, this leads to an attempt to copy a unique_ptr, an operation which is not possible.

Irmairme answered 24/1, 2012 at 14:27 Comment(2)
Thanks for pointing this out. The compiler was misleading me because the error was referencing the member declaration and made no mention of the offending code causing the copy. I imagine this is a deficiency in VS2010 and will hopefully improve with newer releases. My Foo class has a copy constructor, and I was trying to copy the vector out of the source Foo. Shared ownership seems to be the better solution, so switching to shared_ptr did the trick.Ningsia
It looks like a bug in VS2010 I get this error even if my code never tries to call copy-assigment. Disabling the operator= with declaring as private (hence =delete is not supported) solves the problem.Warfeld
T
6

unique_ptr doesn't have copy semantics, so you can't use any methods that would copy the contained object. You can do this with rvalue references by using std::move in the place(s) it's trying to make a copy. Without seeing your code I can't say where that would be.

If it compiles in the second form either you didn't exercise the same code or there's a compiler bug. Both should fail the same way.

Your third example, storing by value is the simplest way unless your objects are large and expensive to store/copy around by value.

Tufts answered 24/1, 2012 at 14:33 Comment(2)
auto_ptr is the one which doesn't obey normal copy semantics, unique_ptr simply doesn't have copy semanticsPhlegm
Your's and Mankarse's answers are very very similar. His, however, made me realize I needed to go on a witch hunt for the offending code (your answer addressed that issue more subtly). You both deserve the accepted answer, though. Thanks for the help!Ningsia
L
4

Often a std::move(iUniquePtr) is missing somewhere (e. g. when using push_back).

Limpkin answered 7/2, 2014 at 11:8 Comment(0)
B
1

The usual problems are erase(), emplace*() and push*(). These will try to shift vector elements around, as one or more than one of them are erased or inserted. While this should work, as std::unique_ptr is movable and shifting is not strictly required, it sometimes does not and the reason are bugs in STL implementations. You may be better off with a std::list for this reason, use std::shared_ptrs, use a std::vector alternative, file a bug, or just use raw pointers, a surprisingly easy and effective solution.

Brinkmanship answered 12/11, 2021 at 8:9 Comment(0)
F
0

An excerpts from www.cplusplus.com

std::unique_ptr::operator=

unique_ptr assignment The object acquires the ownership of x's content, including both the stored pointer and the stored deleter (along with the responsibility of deleting the object at some point). Any object owned by the unique_ptr object before the call is deleted (as if unique_ptr's destructor was called).

But there is a warning too:

This page describes a feature introduced by the latest revision of the C++ standard (2011). Older compilers may not support it.

MSVC 2010 defines operator= as private (non-copyable) but supports swap method.

Funambulist answered 29/5, 2014 at 9:5 Comment(0)
P
-3

You can't use unique_ptr in vector because vector implementation strongly relies on values assign operator, which is private in unique_ptr. Use shared_ptr from boost or other smart ptr implementation from C++11.

Perique answered 24/1, 2012 at 14:28 Comment(3)
C++11 containers are required to work with move-only types like unique_ptr.Mosqueda
I meant the way he used it. But still, thank You, I didn't know about emplace_back.Perique
You don't need to use emplace_back. You can use push_back as long as you give it r-values.Property

© 2022 - 2024 — McMap. All rights reserved.