Calling copy (or assignment) constructor on a pointer?

Started by
8 comments, last by the_edd 15 years, 11 months ago
Hi, I'm trying to prevent copying of resources by asserting when the coder manually does a copy of a resource. The only valid way should be by requesting it from the manager. Currently my code works for regular variables, but not for pointers. Why is that?

using namespace std;

class Resource
{
   //...other code left out.
   public:
        Resource& operator = (Resource const &A){ cout << "Assignment of Resource not allowed, use ResourceManager.add() instead!" << endl << endl; assert(0); };
        Resource(Resource const ©) { cout << "Copy of Resource not allowed, use ResourceManager.add() instead!" << endl << endl; assert(0); } ;
        Resource* operator = (Resource const *A){ cout << "Assignment of Resource not allowed, use ResourceManager.add() instead!" << endl << endl; assert(0); };
        Resource( Resource const *copy) { cout << "Copy of Resource not allowed, use ResourceManager.add() instead!" << endl << endl; assert(0); } ;

};

Resource First("test");  //Set manually for debugging purpose, manager returns *Resource.
Resource Second = First;  //Works fine, assert() is called.

Resource *First = ResourceManager.add("test");
Resource *Second = First; //assert() doesn't work, Second gets a "copy" of First.


How can I prevent the coders from creating a manual copy of the returned *Resource? /Robert
"Game Maker For Life, probably never professional thou." =)
Advertisement
Check out Boost's utility package, and it's noncopyable class. Don't know how Boost do it, but private assignment operator and copy constructor is also an option.
If your clients are using pointers then they're not making copies.
Quote:Original post by Brother Bob
Check out Boost's utility package, and it's noncopyable class. Don't know how Boost do it, but private assignment operator and copy constructor is also an option.
QFE

Σnigma
Quote:Original post by Brother Bob
Check out Boost's utility package, and it's noncopyable class. Don't know how Boost do it, but private assignment operator and copy constructor is also an option.


I just tried this, but it give the same results as my own code. Pointers slip through...

Does anyone know if there's an pointer-operator or similar that can be overloaded?
"Game Maker For Life, probably never professional thou." =)
Let me put it another way. Why do you think you need to prevent pointer copies?

Σnigma
Quote:
I just tried this, but it give the same results as my own code. Pointers slip through...

Does anyone know if there's an pointer-operator or similar that can be overloaded?

No. The solution is to not use pointers -- rather than giving clients a raw Resource*, give them a ResourceHandle or something (by value) that wraps the pointer or whatever other type of reference to the data is most suitable. And make that noncopyable. That will solve your problem.

You can overload operator-> on the ResourceHandle to make it 'act like' a pointer if you want to keep that syntax.

Of course this solution is really just a different form of what others are saying (pointer copies are referential, and lightweight, they don't copy the entire resource just the reference). Wrapping the pointer in an explicit ResourceHandle kind of class would given you a few benefits (such as preventing the client code from manually invoking operator delete), but the primary point is the same with the handle class or with raw pointers.
Quote:Original post by Enigma
Let me put it another way. Why do you think you need to prevent pointer copies?

Σnigma


My ResourceManager class does reference counting, and removes resources that no longer contains any references. If a user does a manual copy of the pointer, the number of references gets invalidated and problems could occur if remove() is called etc.

It might be possible to replace my pointers with a boost shared_ptr instead, but I wanted to code it from ground up for exercise. :)

"Game Maker For Life, probably never professional thou." =)
Well, then you should never expose raw pointers. Use shared_ptr or some kind of handle wrapper.
Quote:Original post by Rasmadrak
If a user does a manual copy of the pointer, the number of references gets invalidated and problems could occur if remove() is called etc.

No, the reference count doesn't get invalidated. The reference count will always be correct for the number of actual Resource objects in existance. The fact that the user has multiple references to a single Resource object should not concern you. In fact it must not concern you, since there is nothing you can do to prevent it.

By all means provide a reference counting system and encourage clients to use it, but there is nothing to be gained by trying to force them to use it.

Σnigma
You have to rely on your clients to have some kind of sense. They're programmers after all (not sure how much that says, really, but you get the idea... :).

With that said, you can do this to stop people taking the address of a resource in the first place:

class Resource{    //...    private:        Resource *operator& () const; // remains undefined};


It uses the same trick as boost::noncopyable. You'll now get a compiler error if you try to take the address of a resource.

I should say though, that this is rather unusual. Overloading the "address-of" operator is considered poor form because it can lead to surprises. However, here there won't be a chance for surprises because it's impossible to take the address in the first place.

Even more howeverer, there are still ways that people can work around this obstruction e.g. by making an array of 1 Resource and using the arrays-decay-to-a-pointer effect, or using boost::addressof.

So IMHO, the best thing to do is to mention clearly in your documentation that Resources are reference counted and cheap to copy. Therefore, clients should avoid pointers-to-Resource.

OTOH, the address of an object is often used as a unique id, for use as a key in a std::map for example. So you might consider implementing appropriate operators <, ==, != etc for this legitimate purpose.

This topic is closed to new replies.

Advertisement