• Advertisement
Sign in to follow this  

auto_ptr Nasties!

This topic is 4482 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, This is a brief discussion about an auto_ptr nasty that i don't know how to resolve. It also leads onto a com_ptr nasty. So supposing you have the following code: main.cpp
#include <memory>

void foo( int** ppInt )
{
  // ...
}

int main( int argc, char* argv[] )
{
 
 auto_ptr< int > pInt;

 pInt.reset( new int );

 // How do you get the address of the T* in auto_ptr. You can't do this:

 int** ppInt = &pInt; // this returns of type auto_ptr< int >*

 // You have to do this
 int* tempPInt = pInt.get();

 foo( &tempPInt );

 return 0;
}



To me this seems horrible because having to extract the contents of the auto_ptr defies the point in having it to begin with. Now you may argue that having architecture where this needs to be done, is in most cases unneeded and bad programming, but consider this. In the Direct3D API there are functions like D3DXCreateTextureFromFile(). One of the parameters to this is of type IDirect3DTexture**. If in your code you are using a com_ptr to clear up your reference counted memory then you have use a similar method to get T**. Now i wrote my own com_ptr, a shared pointer, in a similar style to auto_ptr. It works perfectly, is about as transparent as it can get but i am still undecided about whether to overload operator& for it. If i do overload it then the above T** problem doesn't exist because i can return T** from the operator. With this comes a problem though. If i want to return the address of the com_ptr from a class accessor i cant, because & is overloaded and therefore the accessor returns T** instead of com_ptr< T >*. I hope you understand this horridness, is there any way i can get around this. What would/do you do? ace

Share this post


Link to post
Share on other sites
Advertisement
You could also use &* to convert a smart pointer to a normal pointer. &** would give the address of the pointer, but maybe only of a temprary copy of it. It should work if you let the * function return a non-const reference, but this is very dangerous; as anyone can bypass the smart pointer and modify what is inside it.
I don't know COM, but I assume these are out pointers? You probably don't want to give the COM function direct access to the internals to the smart pointer, this could lead to al kinds of problems. Store the result in a normal pointer first, and put it in the smart pointer only after the call.

Share this post


Link to post
Share on other sites
I guess, that would work. But the idea of smart pointers is to manage the pointer from the beginning of its life time. So surely creating a temporary and giving it value with D3DX... then assigning it to a smart pointer is bad.

This whole idiom irritates.

ace

Share this post


Link to post
Share on other sites
std::auto_ptr sole purpose is to implement resource acquisition is initialization (RAII) and exception safe code (which are not mutually exclusive). std::auto_ptr does not maintain reference counts, it use transfer of ownerships semantics. Despite the bashing std::auto_ptr gets it does exactly what it was set out to do and no more.

Generally you would not use std::auto_ptr with DX because as far as i'm aware DX objects are COM objects (i don't think they are true COM objects though), these objects already have an embedded reference count (hence the addRef & Release). In which case you could either use boost::shared_ptr and read the Using a shared_ptr to hold a pointer to a COM Object or use boost::intrusive_ptr which is like shared_ptr but for objects that already have a reference count (exactly like COM objects), boost::intrusive_ptr just makes the original system automated.

So if i was you i'd use boost::intrusive_ptr or something that does the same as it and in those cases like D3DXCreateTextureFromFile you can simply do:


LPDIRECT3DTEXTURE9 tex_tmp;

D3DXCreateTextureFromFile(...., &tex_tmp);

my_intru_ptr<IDirect3DTexture9> tex_ptr(tex_tmp);


Or something similar to that.

Share this post


Link to post
Share on other sites
Sorry you misunderstand snk_kid, but thanks anyway, it was a mistake on my part.

It was stupid of me to say that i wrote the com_ptr in the same style as auto_ptr. I am completely aware of the sole purpose and methods behind the operation of auto_ptr. I am also aware of how a com_ptr should work. I wrote com_ptr to manage the reference counts as it should.

The question here is more a case of how is it best to attain the value of T** from either of these smart pointers as demonstrated in my code. Like i said, you would have to create a temporary if you do not overload&, then get the address of the temporary. If you do overload operator& then you cannot attain the & of the smart pointer.

I hope you understand.

ace

Share this post


Link to post
Share on other sites
If you allow access to the pointer itself you could write:

com_ptr<Interface> ptr;
ptr = allocate_large_object(); // increments reference count
foo(&ptr); // stores other object in ptr, reference count of large object not decremented

That is not a good thing. A possible solution is to use a special type for out parameters:

com_out_ptr<Interface> temp_ptr;
com_ptr<Interface> ptr;
foo(&temp_ptr);
ptr = temp_ptr;

The code for com_out_ptr would look something like:

template <typename T>
class com_out_ptr {
private:
T* ptr;
destroy() {
if (ptr) ptr->Release();
ptr = 0;
}
friend class com_ptr<T>;
com_out_ptr(const com_out_ptr&) {} // not copy-constructable
public:
com_out_ptr() : ptr(0) {}
~com_out_ptr() { destroy(); }
T** operator &() {
destroy(); // make sure we no longer hold anything before giving access to the pointer
return &ptr;
}
};
// com_ptr can be constructed from a com_out_ptr
template <typename T>
class com_ptr {
// ...
com_ptr(const com_out_ptr<T>& p) {
// take ownership from the
ptr = p.ptr;
const_cast<com_out_ptr<T>&>(p).ptr = 0;
}
}


Share this post


Link to post
Share on other sites
Quote:
Original post by ace_lovegrove
The question here is more a case of how is it best to attain the value of T** from either of these smart pointers as demonstrated in my code. Like i said, you would have to create a temporary if you do not overload&, then get the address of the temporary. If you do overload operator& then you cannot attain the & of the smart pointer.


Yes i recommend you don't not overload the address-of operator the "get" method and taking the address of the underlaying pointer is at least explicit and makes finding subtle bugs easier. The only problem is i don't know what D3DXCreateTextureFromFile does if a pointer already refers to a DX object. If it deals with it inside then it's simple a case of:


D3DXCreateTextureFromFile(...., &my_smart_ptr.get());


I really thinking overloading the address-of operator is a bad idea.

Share this post


Link to post
Share on other sites
See that is what i was thinking. If i had another com_ptr whose local is of type T**, then i could more easily associate it with 'out' parameters. Maybe the com_out_ptr() as you suggested could actually contain another com_ptr, or at least be created from another com_ptr.

Another light idea was to store the pointer as T (LPDIRECT3DDEVICE9) rather than T* (IDirect3DDevice9).

What do you think?

ace

Share this post


Link to post
Share on other sites
Quote:
Original post by snk_kid
Quote:
Original post by ace_lovegrove
The question here is more a case of how is it best to attain the value of T** from either of these smart pointers as demonstrated in my code. Like i said, you would have to create a temporary if you do not overload&, then get the address of the temporary. If you do overload operator& then you cannot attain the & of the smart pointer.


Yes i recommend you don't not overload the address-of operator the "get" method and taking the address of the underlaying pointer is at least explicit and makes finding subtle bugs easier. The only problem is i don't know what D3DXCreateTextureFromFile does if a pointer already refers to a DX object. If it deals with it inside then it's simple a case of:


D3DXCreateTextureFromFile(...., &my_smart_ptr.get());


I really thinking overloading the address-of operator is a bad idea.


I completely agree. It has caused no end of problems, including this one [smile]. The solution there in the code snippet seems awefully simple to me, i could have sworn i tried that.

ace

Share this post


Link to post
Share on other sites
Quote:
Original post by ace_lovegrove
The solution there in the code snippet seems awefully simple to me, i could have sworn i tried that.


Yeah this wont work for anything like std::auto_ptr, if you com_ptr is like boost::intrusive_ptr that just automates AddRef/Release and D3DXCreateTextureFromFile handles things internally that snippet should work with no problems. Just remember that the return type needs to be a reference to a pointer otherwise you'll get complaints about temporaries

Share this post


Link to post
Share on other sites
Right o.

So in the case of the auto_ptr idiom, where youn want to pass T** to a method but not auto_ptr< T>*, what would you do. Surely extracting the value contained in auto_ptr into a temporary is bad?

Any opinions on why auto_ptr doesn't contain a getpp() or similar method?

ace

Share this post


Link to post
Share on other sites
There is no getpp() because getpp() would allow you to bypass the reference counting (or the take-ownership semantics in auto_ptr's case):

// innocent function:
void alloc_new_int(int** out) {
*out = new int(456);
}

auto_ptr<int> ptr( new int(123) ); // fine, ptr owns the int
alloc_new_int(ptr.getpp()); // looks fine to me
// who owns the int(123)?

Share this post


Link to post
Share on other sites
You could stop it by using int *const *const, but why do you need that anyway? I can't think of any reason for passing a ** pointer into a function unless you intend to overwrite the pointer, which you shouldn't, or it's a true pointer-to-array-of-pointers, which it isn't in auto_ptr.

Share this post


Link to post
Share on other sites
Quote:
Original post by ace_lovegrove
Surely extracting the value contained in auto_ptr into a temporary is bad?

I don't see why it would be bad. It's portable and clean. As others have said, directly modifying the pointer kept by auto_ptr is dangerous. When you're writing dangerous code it's best to be explicit about it, both so people know that you really intended to do that and as incentive not to do that in the first place if you can help it.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement