I've defined a class myClass,one of its data members is
std::map<int,data*> dataMap
data is defined as
struct data
{
int d1;
int d2;
std::string d3;
}
Inserting of data to the dataMap is done as follows :dataMap[key] = new data;
the following assignment causes a problem:
myClass a1,a2;
//init a1;
a2 = a1;
I want to use auto_ptr for data instead of data*.how do i do that?-
since there are a problem with destructing "bad pointers for data of a1" after a2 is destructed.std::map<int,std::auto_ptr<data> > is problematic to compile
Upd As you advised I use std::shared_ptr but it still causes a problems :
in VS10
error C2440: 'delete' : cannot convert from 'std::tr1::shared_ptr<_Ty>' to 'void *'
1> with
1> [
1> _Ty=data
1> ]
Can you write sample code pointing the correct way to use shared_ptr
Using auto_ptr is a bad idea (it is deprecated) in general and even worse when combined with standard containers.
Prefer the better designed std::shared_ptr or std::unique_ptr (depending on your situation) and your code will work with one exception: You need to construct the correct smart pointer type when trying to insert it into the container, as the smart pointers are not implicitly constructible from raw pointers.
For this error: error C2440: 'delete' : cannot convert from 'std::tr1::shared_ptr<_Ty>' to 'void *'
You don't need to delete an instant of shared_ptr. The shared_ptr would hold the resource (the new data) with a reference counter, and delete it automatically when the reference counter is 0, meaning that the resource was not used at all. See the manual of shared_ptr for detail
std::auto_ptr is not safe to be used in containers, that why it's been deprecated. Use std::shared_ptr or boost::shared_ptr if available.
You could also use std::unique_ptr if appropriate and available, but it is a bit trickier.
You can use either std::unique_ptr in C++11 if you have a unique ownership (ie, the object will never be shared and only the creator can destruct it again) or you can use std::shared_ptr if you will have shared ownership.
If you're using C++03 you can use boost::shared_ptr or boost::unique_ptr instead.
Related
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())));
}
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.
I'm new to smart pointers, and I'm in the process of hitting every stumbling block.
I have a struct texture_t:
struct texture_t
{
hash32_t hash;
uint32_t width;
uint32_t height;
uint32_t handle;
};
When I try and make a shared_ptr of this struct using this line:
auto texture_shared_ptr = std::make_shared<texture_t>(new texture_t());
I get this error:
error C2664: 'mandala::texture_t::texture_t(const mandala::texture_t &)' : cannot convert parameter 1 from 'mandala::texture_t *' to 'const mandala::texture_t &'
Where is this error coming from and how can I avoid it?
The point of std::make_shared<T>(args...) is to allocate a T object constructed with parameters args.... The idea behind this operation is that std::shared_ptr<T> conceptually maintains two allocated objects:
A pointer to type T.
A record tracking the number of current std::shared_pt<T> and the number of std::weak_ptr<T> objects referring to the object.
When constructing a std::shared_ptr<T> the constructor does a second allocation to construct the record for its internal book keeping. std:make_shared<T>(args...) does just one memory allocation.
The error you saw results from an attempt to construct a mandala::texture_t using a mandala::texture_t* but the only one argument constructor mandala::texture_t has is the copy constructor. However, the pointer doesn't qualify as argument to the copy constructor.
You are not supposed to pass a newed pointer to std::make_shared. You just need to pass arguments from which a texture_t can be constructed to it.
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.
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.