Michele
Michele

Reputation: 3871

how to pop_back shared pointer from vector and convert to unique_ptr

I'm trying to pop_back my shared_pointer from my vector and convert to a unique_ptr. Unfortunately, it's giving a strange compilation message.

IFCCB.cpp:

std::unique_ptr<IFC> IFCCCB::getElementVectorIFC()
{
    return (std::unique_ptr<IFC>(make_unique<IFC>(m_shpVectorIFC.pop_back())));
}

IFCCB.h:

public:
unique_ptr<IFC> getElementVectorIFC();

compile error:

error C2784: 'enable_if::value,std::unique_ptr<_Ty,std::default_delete<_Ty>>>::type std::make_unique(_Types &&...)' : could not deduce template argument for '_Types &&' from 'void'

As far as I can tell, I'm doing what I see elsewhere.

I looked at make_unique info but it doesn't give a very good example, and unique_ptr use. Any ideas?

Upvotes: 1

Views: 2544

Answers (4)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275260

There are many things wrong here:

return (std::unique_ptr<IFC>(make_unique<IFC>(m_shpVectorIFC.pop_back())));

Let us break it down into multiple lines, C++11 style. This isn't quite equivalent, but close:

auto&& a = m_shpVectorIFC.pop_back();
auto&& b = make_unique<IFC>(std::move(a));
auto&& c = std::unique_ptr<IFC>(std::move(b));
return std::move(c);

which isn't a bad technique to start with.

Now you'll get an error that will be more informative.

The first problem is that pop_back() returns void. Fix that with:

auto a = std::move(m_shpVectorIFC.back()); // note a value, as we are about to mutate the vector
m_shpVectorIFC.pop_back();
auto&& b = make_unique<IFC>(std::move(a));
auto&& c = std::unique_ptr<IFC>(std::move(b));
return std::move(c);

we still run into problems. IFC cannot be constructed from a std::shared_ptr<IFC>&&. It cannot. We can make a copy:

auto a = std::move(m_shpVectorIFC.back());
m_shpVectorIFC.pop_back();
auto&& b = make_unique<IFC>(*a);
auto&& c = std::unique_ptr<IFC>(std::move(b));
return std::move(c);

Next, auto&&c is pointless.

auto a = std::move(m_shpVectorIFC.back());
m_shpVectorIFC.pop_back();
auto&& b = make_unique<IFC>(*a);
return std::move(b);

and we might as well store b as a value:

auto a = std::move(m_shpVectorIFC.back());
m_shpVectorIFC.pop_back();
auto b = make_unique<IFC>(*a);
return b;

then some error detecting:

auto a = std::move(m_shpVectorIFC.back());
m_shpVectorIFC.pop_back();
if (!a)
  return {};
auto b = make_unique<IFC>(*a);
return b;

and micro-optimize:

auto a = std::move(m_shpVectorIFC.back());
m_shpVectorIFC.pop_back();
if (!a)
  return {};
auto b = a.unique()?make_unique<IFC>(std::move(*a)):make_unique<IFC>(*a);
return b;

Now, this doesn't return the shared_ptr data, but rather a copy of it. You cannot move the guts of a C++11 shared_ptr into a unique_ptr. You can do it the other way.

Odds are you should be storing a unique_ptr in your vector anyhow.

Upvotes: 4

sjdowling
sjdowling

Reputation: 3022

std::vector::pop_back returns void. That's the reason you are getting that specific error, however once you fix that then you will encounter the problem the others mention.

Upvotes: 3

Richard Hodges
Richard Hodges

Reputation: 69854

i should think something like this would be preferable (assuming m_shpVectorIFC contains unique_ptr objects):

std::unique_ptr<IFC> IFCCCB::getElementVectorIFC()
{
  auto result = std::move(m_shpVectorIFC.back());
  m_shpVectorIFC.pop_back();
  return result;
}

EDIT: ah, just seen the word shared_ptr in there... nope, you have to return a shared_ptr or store a unique_ptr in the container.

Upvotes: 1

Mike Seymour
Mike Seymour

Reputation: 254431

You can't transfer ownership from a shared pointer to a unique pointer. Once ownership is shared, it remains shared.

Either store unique pointers if you don't need to share ownership with the container, or continue to use shared pointers after removing from the container if you do.

Upvotes: 5

Related Questions