How push_back unique_ptr parameter onto vector of shared ptrs - c++

I'm having a tough time pushing back a unique_ptr from my method parameter onto a vector of shared pointers.
IFCCB.h:
private:
vector<shared_ptr<IFC>> m_shpVectorIFC;
public:
void addElementVectorIFC(unique_ptr<IFC> rupIFC);
IFCCB.cpp:
void IFCCB::addElementVectorIFC(unique_ptr<IFC> rupIFC)
{
m_shpVectorIFC.push_back(std::unique_ptr<IFC>(new IFContent(rupIFC)));
}
I'm getting the error:
C2664: 'IFC::IFC(const IFC &)' : cannot convert argument 1 from
'std::unique_ptr>' to 'IFO *'
In this case, IFO is the heirarchical parent of IFC. I'm not sure why it's looking at that.
I've looked at vector info and shared_ptr info, as well as using unique_ptr with standard library containers.
Any ideas? I'm not used to working with shared_ptrs and unique_ptrs.

The problem is that push_back takes the container's value_type, which is shared_ptr<IFC>, but you are passing it a unique_ptr<IFC> and the conversion from unique_ptr to shared_ptr uses an explicit constructor and can only be done from a unique_ptr rvalue, so the argument cannot be implicitly converted to shared_ptr.
To make it work you need to use std::move to convert the unique_ptr to an rvalue and then either do the conversion to shared_ptr explicitly:
unique_ptr<IFC> p;
// ...
m_shpVectorIFC.push_back(std::shared_ptr<IFC>(std::move(p)));
Or use emplace_back instead, because that function can use explicit constructors to construct the new container element:
m_shpVectorIFC.emplace_back(std::move(p)));
I'm not convinced your code that creates a new unique_ptr is correct (why can't you just insert rupIFC into the container using either of the solutions shown above?) but if that's really what you want to do, the error you get is because you are trying to pass unique_ptr<IFC> to the IFContent constructor, which takes a IFO* not a unique_ptr<IFC>. To make that compile you need to get the raw pointer out of rupIFC:
std::unique_ptr<IFC>(new IFContent(rupIFC.get()))
However this is probably unsafe, because the pointer you passed to the IFContent constructor will be deleted at the end of the function when rupIFC is destroyed, so maybe you meant to release it:
std::unique_ptr<IFC>(new IFContent(rupIFC.release()))
N.B. as dlf's answer says, there is no point creating a unique_ptr if you just want to convert it to a shared_ptr immediately, so you could simply do:
m_shpVectorIFC.emplace_back(std::make_shared<IFContent>(rupIFC.release()));

Based on your addendum, you will need to use unique_ptr::get() to provide the IFContent constructor with the raw pointer it wants. Depending on what it does with that pointer, you may actually need to use release instead to prevent double-deletion. Also, no need to create an intermediate unique_ptr when it's just going to be converted right into a shared_ptr anyway:
void IFCCB::addElementVectorIFC(unique_ptr<IFC> rupIFC)
{
m_shpVectorIFC.push_back(std::shared_ptr<IFC>(new IFContent(rupIFC.get())));
}

Related

Cannot understand how to add new object to std::list<std::unique_ptr<classname>>

I have strange issue with std::list of unique_ptr's.
Class slFlyingMonster is derived from class slMonster.
Following code works:
std::unique_ptr<slMonster> ptr(new slFlyingMonster(md));
But this code:
std::list<std::unique_ptr<slMonster>> mMonsters;
mMonsters.push_back(new slFlyingMonster(md));
throws error:
"Error 1 error C2664: 'void
std::list>,std::allocator>>>::push_back(const
std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : cannot convert
argument 1 from 'slFlyingMonster *' to
'std::unique_ptr> &&'"
While I understand, that something is wrong, like std::list.push_back() is not the same as =, but I cannot figure out how to correctly add new class as unique_ptr to list. Any suggestions would be very welcome.
Use push_back when you have an object of the type which your list contains, and you want to push its copy. Normally, if you don't have such an object yet (in your case, you don't), you're better off initialising a new object directly in the list — using emplace_back instead:
std::list<std::unique_ptr<slMonster>> mMonsters;
mMonsters.emplace_back(new slFlyingMonster(md));
However, as #SebastianRedl correctly pointed out in the comments, the above has a problem of not being exception-safe. If the internal allocation of a new node inside std::list throws, the new slFlyingMonster instance would be leaked. emplace_back is not the correct choice when one of the arguments is an unprotected resource (such as a raw pointer owning memory).
So you actually want to construct a wrapper smart pointer and push it into the list. In C++14, you can do this with std::make_unique:
std::list<std::unique_ptr<slMonster>> mMonsters;
mMonsters.push_back(std::make_unique<slFlyingMonster>(md));
With plain C++11, you can either implement your own make_unique, or explicitly create the smart pointer:
std::list<std::unique_ptr<slMonster>> mMonsters;
mMonsters.emplace_back(std::unique_ptr<slMonster>(new slFlyingMonster(md)));
You may use emplace_back:
std::list<std::unique_ptr<slMonster>> mMonsters;
mMonsters.emplace_back(new slFlyingMonster(md));
or push_back a std::make_unique:
std::list<std::unique_ptr<slMonster>> mMonsters;
mMonsters.push_back(std::make_unique<slFlyingMonster>(md));
or std::move of a std::unique_ptr
std::list<std::unique_ptr<slMonster>> mMonsters;
std::unique_ptr<slMonster> p(new slFlyingMonster(md));
mMonsters.push_back(std::move(p));
The constructor std::unique_ptr<T>(T*) is explicit, so T* cannot construct implicitly a std::unique_ptr.
Use mMonsters.emplace_back so the object is created from the argument given in parameters.

unique_ptr and polymorphism

I have some code that currently uses raw pointers, and I want to change to smart pointers. This helps cleanup the code in various ways. Anyway, I have factory methods that return objects and its the caller's responsibility to manager them. Ownership isn't shared and so I figure unique_ptr would be suitable. The objects I return generally all derive from a single base class, Object.
For example,
class Object { ... };
class Number : public Object { ... };
class String : public Object { ... };
std::unique_ptr<Number> State::NewNumber(double value)
{
return std::unique_ptr<Number>(new Number(this, value));
}
std::unique_ptr<String> State::NewString(const char* value)
{
return std::unique_ptr<String>(new String(this, value));
}
The objects returned quite often need to be passed to another function, which operates on objects of type Object (the base class). Without any smart pointers the code is like this.
void Push(const Object* object) { ... } // push simply pushes the value contained by object onto a stack, which makes a copy of the value
Number* number = NewNumber(5);
Push(number);
When converting this code to use unique_ptrs I've run into issues with polymorphism. Initially I decided to simply change the definition of Push to use unique_ptrs too, but this generates compile errors when trying to use derived types. I could allocate objects as the base type, like
std::unique_ptr<Object> number = NewNumber(5);
and pass those to Push - which of course works. However I often need to call methods on the derived type. In the end I decided to make Push operate on a pointer to the object stored by the unique_ptr.
void Push(const Object* object) { ... }
std::unique_ptr<Object> number = NewNumber(5);
Push(number.get());
Now, to the reason for posting. I'm wanting to know if this is the normal way to solve the problem I had? Is it better to have Push operate on the unique_ptr vs the object itself? If so how does one solve the polymorphism issues? I would assume that simply casting the ptrs wouldn't work. Is it common to need to get the underlying pointer from a smart pointer?
Thanks, sorry if the question isn't clear (just let me know).
edit: I think my Push function was a bit ambiguous. It makes a copy of the underlying value and doesn't actually modify, nor store, the input object.
Initially I decided to simply change the definition of Push to use
unique_ptrs too, but this generates compile errors when trying to use
derived types.
You likely did not correctly deal with uniqueness.
void push(std::unique_ptr<int>);
int main() {
std::unique_ptr<int> i;
push(i); // Illegal: tries to copy i.
}
If this compiled, it would trivially break the invariant of unique_ptr, that only one unique_ptr owns an object, because both i and the local argument in push would own that int, so it is illegal. unique_ptr is move only, it's not copyable. It has nothing to do with derived to base conversion, which unique_ptr handles completely correctly.
If push owns the object, then use std::move to move it there. If it doesn't, then use a raw pointer or reference, because that's what you use for a non-owning alias.
Well, if your functions operate on the (pointed to) object itself and don't need its address, neither take any ownership, and, as I guess, always need a valid object (fail when passed a nullptr), why do they take pointers at all?
Do it properly and make them take references:
void Push(const Object& object) { ... }
Then the calling code looks exactly the same for raw and smart pointers:
auto number = NewNumber(5);
Push(*number);
EDIT: But of course no matter if using references or pointers, don't make Push take a std::unique_ptr if it doesn't take ownership of the passed object (which would make it steal the ownership from the passed pointer). Or in general don't use owning pointers when the pointed to object is not to be owned, std::shared_ptr isn't anything different in this regard and is as worse a choice as a std::unique_ptr for Push's parameter if there is no ownership to be taken by Push.
If Push does not take owenrship, it should probably take reference instead of pointer. And most probably a const one. So you'll have
Push(*number);
Now that's obviously only valid if Push isn't going to keep the pointer anywhere past it's return. If it does I suspect you should try to rethink the ownership first.
Here's a polymorphism example using unique pointer:
vector<unique_ptr<ICreature>> creatures;
creatures.emplace_back(new Human);
creatures.emplace_back(new Fish);
unique_ptr<vector<string>> pLog(new vector<string>());
for each (auto& creature in creatures)
{
auto state = creature->Move(*pLog);
}

How to convert an object instance to shared_ptr instance

Suppose I had two shared_ptr types such as
boost::shared_ptr<ObjA> sptrA;
boost::shared_ptr<ObjB> sptrB;
Now suppose that sptrA->SomeMethod() returned a simple ObjB type (not a shared ptr). Is it possible for me to store that type somehow in sptrB ? So that I could do something like this so that the returned type instance is automatically converted to boost_shared ptr
sptrB = sptrA->SomeMethod();
I asked this question just of curiosity and whether it is possible or not ?
The most standard way of creating boost:shared_ptr objects is to use the make_shared function provided by Boost:
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
struct A {};
A generator() {
return A();
}
int main()
{
using namespace boost;
shared_ptr<A> p = make_shared<A>(generator());
return 0;
}
Since the generator() function returns an A object by value, the syntax above implies that new is invoked with the copy contructor of A, and the resulting pointer is wrapped in a shared-pointer object. In other words, make_shared doesn't quite perform a conversion to shared pointer; instead, it creates a copy of the object on the heap and provides memory management for that. This may or may not be what you need.
Note that this is equivalent to what std::make_shared does for std::shared_ptr in C++11.
One way to provide the convenient syntax you mentioned in your question is to define a conversion operator to shared_ptr<A> for A:
struct A {
operator boost::shared_ptr<A>() {
return boost::make_shared<A>(*this);
}
};
Then you can use it as follows:
shared_ptr<A> p = generate();
This will automatically "convert" the object returned by the function. Again, conversion here really means heap allocation, copying and wrapping in a shared pointer. Therefore, I am not really sure if I'd recommend defining such a convenience conversion operator. It makes the syntax very convenient, but it, as all implicit conversion operators, may also mean that you implicitly cause these "conversions" to happen in places you didn't expect.
Since C++ 11 you can use std::make_shared<T>() function (link)
Example:
int a = 10;
std::shared_ptr<int> shared_a = std::make_shared<int>(a);
This depends on precisely what ObjA::SomeMethod returns - a copy, a reference or a pointer. In the first two cases it would not be feasible to wrap it into a shared_ptr (because shared_ptr needs a pointer).
The third case is possible, but you must proceed with caution. Make sure that once you wrap a pointer to an object into a shared_ptr, no one else attempts to manage the lifetime of that object.
For example, if you return a raw pointer, wrap it into a shared pointer and then, at some point later in the program, someone deletes that same pointer, you will have a problem.

List of smart pointers - Managing object lifetime and pointer validity

I have a list of smart pointers where each pointer points to a separate Entity class.
std::list<std::unique_ptr<Entity>> m_entities;
I would like the constructor to handle the assigning of each pointer to a std::list class as it is "automatically" handled by the code on class instantiation. However, if this design is bad then I would welcome a better alternative as it only makes sense to me coming from a C# background.
Entity::Entity(Game &game)
: m_game(game),
m_id(m_game.g_idGenerator->generateNewID())
{
m_game.m_entities.push_back(std::unique_ptr<Entity>(this));
}
The main problem I have encountered with this method is that the Entity class' lifetime is unmanaged by the Entity class.
For example if I allocate an Entity class on the stack it will call the Entity destructor after leaving the method in which it was allocated and the pointer will no longer be valid.
I therefore considered the alternative of creating a smart pointer, allocating the Entity class to the heap and then explicitly adding the pointer to the list.
std::unique_ptr<Entity> b(new Entity(*this));
m_entities.push_back(b); // ERROR
This produces the following error
error C2664: 'void std::list<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'std::unique_ptr<_Ty>' to 'std::unique_ptr<_Ty> &&'
What would be considered the best approach for allocating each pointer to the list and is a constructor based version possible?
I'm currently thinking that it is the list of smart pointers that should handle the lifetime for each Entity class and that assigning pointers in a constructor is not a good design choice. In that case I should probably create a CreateEntity method that adds the pointer to list rather than let the constructor handle it. Is this better?
I considered what type of smart pointer would be appropriate for this operation after reading through questions found here, here and here (offsite). It is difficult to get an exact answer based on what I've read so far though as they all offer somewhat conflicting advice.
Using constructor this way is definitely not good idea because constructor has no information about how object is created and controlled - on the stack, statically, dynamically by some smart pointer, dynamically by dumb pointer?
To solve this problem you could use static factory method to create Entity instances:
class Entity
{
public:
// Variant with unique ownership
static void CreateGameEntity(Game& game)
{
std::unique_ptr<Entity> p(new Entity());
game.m_entities.push_back(std::move(p));
}
// OR (you cannot use both)
// Variant with shared ownership
static std::shared_ptr<Entity> CreateGameEntity(Game& game)
{
std::shared_ptr<Entity> p(new Entity());
game.m_entities.push_back(p);
return p;
}
private:
// Declare ctors private to avoid possibility to create Entity instances
// without CreateGameEntity() method, e.g. on stack.
Entity();
Entity(const Entity&);
};
Which smart pointer to use? Well, this depends on your design. If Game object solely owns Entity instances and completely manages their lifetime, using std::unique_ptr is OK. If you need some kind of shared ownership (e.g. you have several Game objects that can share same Entity objects) you shall use std::shared_ptr.
Also in case of unique ownership you may use Boost Pointer Container library. It contains specialized owning pointer containers like ptr_vector, ptr_list, ptr_map etc.
I won't comment on your design questions, but to fix your error, change your code to either:
m_entities.push_back(std::unique_ptr<Boundary>(new Boundary(*this, body)));
or:
std::unique_ptr<Boundary> b(new Boundary(*this, body));
m_entities.push_back(std::move(b));
The reason is that b in your code is an lvalue, but std::unique_ptr<> is a move-only type (i.e. has no copy constructor).
The problem in your code is that you try to move a std::unique_ptr<T> from an l-value. The instantiations of std::unique_ptr<T> are non-copyable and are only movable. To move from an l-value you need to explicitly do so:
this->m_entities.push_back(std::move(b));
The call to std::move() won't really move anything but it does yield a type which indicates to the compiler that the object can be moved.
To address the issue with the stack-created instance, you could simply add a parameter to the constructor that tells it to not add the new instance to the list, eg:
Entity::Entity(Game &game, bool AddToList = true)
: m_game(game),
m_id(m_game.g_idGenerator->generateNewID())
{
if (AddToList) m_game.m_entities.push_back(this);
}
.
{
...
Entity e(game, false);
...
}
Another option might be to add a destructor to Entity that removes it from the list if it is still present, but that might get a little complex trying to avoid conflicts between direct Entity destructions and unique_ptr destructions.

Best practice for std::auto_ptr

I'm just getting used to smart pointers using std::auto_ptr.
Assume that I want to call a function with both auto_ptr and normal Pointers.
auto_ptr<uint32> data_smart(new uint32[123])]);
uint32 data_fix[123];
uint32* data_dumb = new uint32[123];
processData(data_smart);
processData(data_fix);
processData(data_dumb);
What is the best practice for this without overloading? Having the processData function with a uint32* argument? Can I cast the smart pointer to uint32* for this case with .get()? Or what is the way I should do it?
Thanks in advance!
1.
auto_ptr<uint32> data_smart(new uint32[123])]);
Don't do that. auto_ptr works with scalars only (it calls delete rather than delete[]).
2.
auto_ptr owns the object it points to, so unless you want to pass the ownership to that function (in your code you don't), the function should accept a normal pointer. So you should change the call to:
processData(data_smart.get());
in order to explicitly express that data_smart continues to own the object.
EDIT: Noah Roberts' comment on your question is the bigger issue here, but this answers the question asked even if the example code is wrong....
... without overloading ...
If you want to do it without overloading, the only option that's going to work for all of these is to make the method take a dumb pointer parameter.
Can I cast the smart pointer to uint32* for this case?
No. Use std::auto_ptr<t>::get().
First of all, you don't initialize auto_ptr with a pointer to array. It's not supported, and you'll end up with memory leaks. std::auto_ptr handles only single objects.
If you still want to use std::auto_ptr, but for single objects only, you need to remember that std::auto_ptr transfers ownership in copy constructor. That means that your local auto_ptr (data_smart) won't hold any memory after you call processData if you pass data_smart by value.
In the end, you probably want to use boost::scoped_array or boost::shared_array.
Best practice is to not use auto_ptr. It will be deprecated in C++0x and replaced by std::unique_ptr (Reference: C++0x Draft Standard, Appendix D, Paragraph 10). In the meantime, alternatives include std::tr1::shared_ptr and boost::scoped_ptr.
But your example is an array, and those pointer types are not for arrays. You can use boost::shared_array for that.
However the Standard itself does not have array smart pointers. That’s probably because they believe you should be using std::vector instead (or std::array for fixed size arrays when you know the size at compile time). Given that, you could do the following:
std::vector<uint32> dataVector;
data.reserve(123);
// or, if the size is always 123:
std::tr1::array<uint32, 123> dataArray;
Now, you can call your function that accepts a regular plain-old uint32* because both vectors and std::tr1::arrays have methods to give you access to the data as a pointer to a C-style array:
processData(&dataVector[0]);
processData(dataArray.data());
I would strongly recommend adding bounds-checking if you are going to do this. Pass a second argument to processData with the size of the array:
processData(&dataVector[0], dataVector.size());
And if you can abandon C-style pointer/arrays entirely, a better way might be to pass by reference:
void processData(std::vector<uint32>& data) {
// process the data
}
// call it like this:
processData(dataVector);
But this only works for vectors, not std::tr1::arrays or any other container. So, taking it one step further, you could use a template that accepts iterators:
template <class AnIterator>
void processData(AnIterator begin, AnIterator end) {
for (AnIterator it = begin; it != end; ++it) {
// process each item
}
}
// call it like this
processData(dataVector.begin(), dataVector,end());
// or like this
processData(dataArray.begin(), dataArray.end());
// or even like this (assume c_data is a C-style array):
processData(c_data, c_data + number_of_items_in_c_data);
The last one works because pointers to C-style arrays can be used as iterators.
In your situation using a vector is the safest choice:
std::vector<uint32> data(123);
The signature of processData should ideally be:
void processData(const std::vector<uint32> & data);
However, this one is more frequently used:
void processData(uint32 * bytes, int length);
In both cases you can use the vector:
// 1
processData(data);
// 2
processData(data.data(), data.size());
Not withstanding why you should want to use auto and dumb (as you put it) pointers for the same data to the same name function without overloading, auto_ptr cannot be used on arrays because it calls the wrong sort of delete.
Have a look at this: http://learningcppisfun.blogspot.com/2007/05/custom-deleters-with-smart-pointers.html
Also have a look at this SO question regarding smart pointers to arrays: auto_ptr for arrays
It amuses me that the data_smart variable is the dumbest of the three. That is, when that scope ends, the auto_ptr destructor is going to call delete on its pointer and not delete[] which leads to UB (which is worse than the possible memory leak from data_dumb).
So, the point is don't use auto_ptr for arrays, use vector.
Onto the real question. First, if possible use reference arguments instead of pointer arguments. If this isn't possible use bare pointers and auto_ptr::get() gives access to the underlying pointer.
Ignoring the already HAMMERED don't use auto_ptr on array.
What is the best practice for this without overloading?
It appears your method will not take ownership, so the remaining question is will it be changed?
Having the processData function with a uint32* argument?
processData( uint32* ) Thats one option, but maybe not the best.
processData( uint32[123] ) if your not editing (123 is starting to push some copying).
processData( uint32 &[123] ) by ref and apply const as necessary.
Can I cast the smart pointer to uint32* for this case with .get()?
You can get the pointer content of the smart pointer using get(), it's already 'typed' so no need to cast it.
Aside:
Data and manipulation of at such a raw level should be in the one class, you probably don't even need to pass what should be a member variable into a member function.