Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using std::vec "push_back" on a vector of objects which contain unique_ptrs

34 views
Skip to first unread message

bitrex

unread,
Aug 24, 2016, 3:28:56 PM8/24/16
to
Having a bit of trouble with code like this (still getting acquainted
with 21st century C++):

#include <vector>
#include <memory>

template <typename T>
class Foo {
public:
Foo() = default;
~Foo() = default;

private:
std::unique_ptr<std::vector<T>> baz =
std::unique_ptr<std::vector<T>>(new std::vector<T>());
};

template <typename T>
class Bar {
public:
Bar(size_t foonum)
{
for (size_t n = 0; n < foonum; ++n) {
bip->push_back(Foo<T>());
}
}

~Bar() = default;

private:
std::unique_ptr<std::vector<Foo<T>>> bip =
std::unique_ptr<std::vector<Foo<T>>>(new std::vector<Foo<T>>());

};

int main()
{
Bar<uint32_t> bar(10);
return 0;
}

Seems like it's complaining about the new Foo<T> object not being able
to be pushed back into "bip" because it can't use the default
copy-constructor for that class (as unique_ptrs aren't copyable.) What's
the correct way to do this?

Victor Bazarov

unread,
Aug 24, 2016, 3:53:22 PM8/24/16
to
On 8/24/2016 3:28 PM, bitrex wrote:
> Having a bit of trouble with code like this (still getting acquainted
> with 21st century C++):
>
> #include <vector>
> #include <memory>
> [.. code defining template Foo<T> snipped ..]
> [.. code involving a vector<Foo<T>> snipped ..]
>
> Seems like it's complaining about the new Foo<T> object not being able
> to be pushed back into "bip" because it can't use the default
> copy-constructor for that class (as unique_ptrs aren't copyable.) What's
> the correct way to do this?

The correct way to do *what*? You can't put a non-copyable object in a
standard container, AFAIK, because being copy-constructible is one of
the requirements for a contained type, at least in C++ 98.

V
--
I do not respond to top-posted replies, please don't ask

bitrex

unread,
Aug 24, 2016, 4:12:20 PM8/24/16
to
I found adding a user-defined copy-constructor that assigns a new
unique_ptr manually seems to work, at least in C++11:

template <typename T>
class Foo {
public:
Foo() = default;

Foo(const Foo& foo)
{
baz = std::make_unique<std::vector<T>>(*foo.baz);

Alf P. Steinbach

unread,
Aug 24, 2016, 4:36:23 PM8/24/16
to
On 24.08.2016 21:28, bitrex wrote:
> Having a bit of trouble with code like this (still getting acquainted
> with 21st century C++):
>
> #include <vector>
> #include <memory>
>
> template <typename T>
> class Foo {
> public:
> Foo() = default;
> ~Foo() = default;
>
> private:
> std::unique_ptr<std::vector<T>> baz =
> std::unique_ptr<std::vector<T>>(new std::vector<T>());
> };

Oh my. Much of the point of `std::vector` is that it automates the
memory management. Adding memory management on top of that is, well, not
needed.


> template <typename T>
> class Bar {
> public:
> Bar(size_t foonum)
> {
> for (size_t n = 0; n < foonum; ++n) {
> bip->push_back(Foo<T>());
> }
> }
>
> ~Bar() = default;
>
> private:
> std::unique_ptr<std::vector<Foo<T>>> bip =
> std::unique_ptr<std::vector<Foo<T>>>(new std::vector<Foo<T>>());
>
> };

Ditto, that's just asking for problems.


> int main()
> {
> Bar<uint32_t> bar(10);
> return 0;

`return 0;` is the default for `main`.


> }
>
> Seems like it's complaining about the new Foo<T> object not being able
> to be pushed back into "bip" because it can't use the default
> copy-constructor for that class (as unique_ptrs aren't copyable.) What's
> the correct way to do this?

Just use `std::vector` directly.

[code]
#include <vector>
#include <stddef.h>

template< class Type >
class Foo
{
private:
std::vector<Type> baz;

public:
Foo() = default;
~Foo() = default;
};

template < class Type >
class Bar
{
private:
std::vector<Foo<Type>> bip;

public:
Bar( int const foonum )
: bip( foonum, Foo<Type>() )
{}

~Bar() = default;

};

auto main()
-> int
{
Bar<int> bar{ 10 };
(void) bar;
}
[/code]


Cheers & hth.,

- Alf

mark

unread,
Aug 24, 2016, 5:10:20 PM8/24/16
to
You can add a move constructor to Foo:

#include <vector>
#include <memory>

template <typename T>
class Foo {
public:
Foo() = default;
~Foo() = default;
Foo(Foo&& ) = default;

Victor Bazarov

unread,
Aug 24, 2016, 5:15:28 PM8/24/16
to
Is that an exercise? What is the reason for using 'std::unique_ptr' in
your design? Is there such a reason? IOW, why do you thinkn you need
specifically 'std::unique_ptr'? Would not 'std::shared_ptr' do? I
cannot tell from the code you showed because there is no design intent
obvious in it. And *that's* why I asked "to do *what*". You still
haven't answered that question, remember?

The original application of 'unique_ptr' was to assist in _move_
operations. The owned object is created once, and only destroyed once,
when the final 'unique_ptr' object that "owns" it is destroyed. Between
the creation and the destruction, the ownership is actually transferred.
Splitting responsibilities of 'auto_ptr' between 'shared_ptr' and
'unique_ptr' solved some serious problems, IIRC...

bitrex

unread,
Aug 24, 2016, 7:36:12 PM8/24/16
to
Ah okay. The simple example above did not include the rest of the
code...the purpose is because unlike the example, there are actually
class methods which are returning heap-allocated vector objects and
assigning them to that "unique_ptr."

bitrex

unread,
Aug 24, 2016, 9:18:45 PM8/24/16
to
Okay, it seems my point of confusion was where std::vector allocates the
container items. If it's always on the heap by default, then there's
indeed no point in doing what I'm doing. Too used to the "C-style" arrays...

bitrex

unread,
Aug 25, 2016, 5:32:33 AM8/25/16
to
On 08/24/2016 03:28 PM, bitrex wrote:
> Having a bit of trouble with code like this (still getting acquainted
> with 21st century C++):

Here's a working example of what I was trying to do that's better, I think.

Foo is a class with a regular std::vector member variable containing a
bunch of some integer type T.

Bar is a class containing a std::vector of some number of unique_ptrs
to class Foo<T> which are pushed back onto the vector when an object of
type Bar is instantiated. Class Bar can then sort the vector of Foo
objects by pointer instead of by value, and pick the "best" one.

If my understanding is correct, because the vector in Bar contains
unique_ptrs to Foo, when Bar goes out of scope all the Foo objects and
their vectors of type T will be released from memory automatically.

http://pastebin.com/68NqSZg8

Ian Collins

unread,
Aug 25, 2016, 5:41:57 AM8/25/16
to
Your understanding is correct. I haven't looked at the code, but in many
cases std::vector<std::unique_ptr<T>> can be used as a standard
replacement for boost::ptr_vector<T>.

--
Ian
0 new messages