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.
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'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.
I have a template class (Node is an inner class within a BST). It's now time to free up the memory; Given that either the key or the value (or both) may be pointers, I must figure out how to free them if they are.
See an example:
~Node( void )
{
if ( is_pointer< TValue >( Value ) )
{
delete Value;
Value = NULL;
}
if ( is_pointer< TComparable >( Key ) )
{
delete Key;
Key= NULL;
}
}
The implementation behind the is_pointer< T > function works (Taken from here), however as soon as I press delete on either Key or Value, I get the following:
Error 13 error C2440: 'delete' : cannot convert from 'esc::Shader' to 'void *' c:\programming\c++\git\escalator\engine\engine\searchtree.hpp 131
Error 14 error C2440: 'delete' : cannot convert from 'esc::ShaderComparable' to 'void *' c:\programming\c++\git\escalator\engine\engine\searchtree.hpp 137
Error 12 error C2679: binary '=' : no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion) c:\programming\c++\git\escalator\engine\engine\searchtree.hpp 130
I've tried static_cast, dynamic_cast, reinterpret_cast, etc, but neither of these appear to work.
What's a good solution?
I must figure out how to free them if they are.
Don't. Really- don't. That's the user's problem- and he can supply a smart pointer if he wants this behaviour. After all, what if I want to map non-owning pointers? Or need a custom deleter?
Also, your code does not work because you compile the dead code if branches anyway, because you did not use a specialization.
It looks like you are storing copies of elements of type T instead of pointers as commonly done. If your declaration is T Value; than your Node class is normally not responsible for deleting Value object.
This really depends on what kind of software you're working on here. Unless it's some quick test and you're not going to reuse the code, then yes, don't bother distinguishing pointers from objects or arrays. But if you're writing library code and you think your component will be reused by other people, then you should take care about cleaning after yourself. STL vector has been doing this successfully since the dawn of times. Last I saw the code they've been calling a Destroy function for (First,Last) elements of the vector with an value tag passed into the function as the third argument. And if elements are just plane scalar pointers (meaning int* for instance), then destructors need not be called. Obviously the real data has been allocated by the user and only addressed of the data has been stored in a vector, so it should not be deallocated. But if it's objects that are stored in the vector (objects of a user-defined class for instance, class A, lets say), then destructors need to be called for each element in the vector ~A() and after all of them ran to the end, the contiguous memory chunk that used to store the elements should be deallocated through the use of vectors allocator. For more information you can easily open vectors implementation, it's all in the header file, look at ~vector() implementation and let that guide you.
I got a structure and a function like the following:
struct MYOVERLAPPED : public OVERLAPPED
{
//...
};
void func1(std::unique_ptr<MYOVERLAPPED> pBuf)
{
//...
};
I am obtaining a pointer to MYOVERLAPPED which i want to pass to the func1-function.
The problem i encounter is, that no matter what i try i get the following errors :
What i did try already are the following:
Try1:
std::unique_ptr<OVERLAPPED> pOver(//....)
HandleAcceptIndication(std::move(pOver));
Error: Error 1 error C2440: 'initializing' : cannot convert from
'_OVERLAPPED **' to 'MYOVERLAPPED *'
Try2:
HandleAcceptIndication(new ACCEPT_OVERLAPPED);
Error 1 error C2664: 'HandleAcceptIndication' : cannot convert
parameter 1 from 'MYOVERLAPPED *' to 'std::unique_ptr<_Ty>'
Anyone knows how i can pass this casted pointer of OVERLAPPED to MYOVERLAPPED to the function and why Try2 does not work either since i casually use std::unique_ptr<MYOVERLAPPED> pO(new MYOVERLAPPED) which does work...?
While you cannot convert from std::unique_ptr<base> to std::unique_ptr<derived> directly, it is not too hard to write a cast function that will be safe (i.e. not leak the resource under any circumstance, and only succeed if the cast is valid:
template <typename Dst, typename Src>
std::unique_ptr<Dst> unique_dynamic_cast( std::unique_ptr<Src>& ptr ) {
Src * p = ptr.release(); // [1]
std::unique_ptr<Dst> r( dynamic_cast<Dst*>(p) ); // [2]
if ( !r ) {
ptr.reset( p ); // [3]
}
return r; // [4]
}
The basic idea is that we need to extract the pointer from the std::unique_ptr and set it aside in [1]. We cannot try dynamic_cast directly, as if that fails, ptr would have released ownership, and the memory would be leaked. Then we try and perform the dynamic_cast [2] from the local pointer to the requested type of pointer and pass ownership onto the r result unique pointer. If the dynamic_cast fails, then r will be null, and we need to return ownership of the memory to the original std::unique_ptr [3], for calling code to decide what to do with it. We then return the converted std::unique_ptr to the caller in [4].
This doesn't work because you're trying to cast the wrong way in the inheritance hierarchy. You're trying to convert from Base* to Derived* implicitly.
unique_ptr<A> and unique_ptr<B> are unrelated types. You can't convert between them unless an implicit conversion exists between A* and B* (thanks UncleBens), which is not true in this case. Also you should not cast down the inheritance hierarchy with an instance that is not the subclass you are casting to. In this case, you're trying to cast a OVERLAPPED to a MYOVERLAPPED which is an invalid cast because an OVERLAPPED is not a MYOVERLAPPED. That's why you can't convert between the unique_ptr types in the first place.
If you are just trying to pass a unique_ptr to func1, you can do it like this:
func1(shared_ptr<MYOVERLAPPED>(new MYOVERLAPPED));
Also, by passing a unique_ptr to a function, the pointer in the original one gets set to NULL. Consider using references or shared_ptrs if you are not creating the unique_ptr as a temporary and passing it to the function and you need to use the same instance later.