Re: Help with Vectors of Classes and Derived Classes
I suggested having the operator overload as const because it is the one you are more likely to call "without thinking", and therefore would be more likely to lead to a programmer cloning by mistake. After all, it would not fail to compile if you used this to call a const method, whereas making the operator return the const pointer, it would fail to compile if you thoughtlessly used the operator and tried to call a non-const method.
Re: Help with Vectors of Classes and Dervived Classes
I might ask you how often you want to clone anyway. I cannot think of many occasions I have wanted to clone an abstract object. I pretty much never copy-construct anything, in fact, except for function objects (and smart-pointers).
If you are cloning an abstract object, ask yourself whether you should:
- be using a plain reference-counted shared-pointer (they are pointing to the same object).
- Have a concrete class that has a reference-counted shared-pointer to an abstract class, and use that for your abstraction. (Is this another adapter?)
Suppose, for example, I have an abstract collection of objects called Coll and I want an iterator to be able to run through the collection.
Now your iterator would probably have a pointer to Coll and some either item relating to its current position. In order to get to the data, or to advance, your iterator would have to consult Coll and pass it the positioning data too.
You must consider the fact that the positioning data itself could be dependent on the implementation of Coll, and therefore consider that you actually have an abstract class, let's call it Pos. We can now use this abstract class Pos to iterate through our data.
But what about our iterator? Easy - our iterator will have a shared-pointer to a Pos and will use this Pos to access data and to increment itself, and to compare itself to another Pos. But iterator itself (which is going to be cloned) is now a concrete class.
Re: Help with Vectors of Classes and Dervived Classes
Quote:
Originally Posted by NMTop40
I might ask you how often you want to clone anyway. I cannot think of many occasions I have wanted to clone an abstract object. I pretty much never copy-construct anything, in fact, except for function objects (and smart-pointers).
If you are cloning an abstract object, ask yourself whether you should:
- be using a plain reference-counted shared-pointer (they are pointing to the same object).
- Have a concrete class that has a reference-counted shared-pointer to an abstract class, and use that for your abstraction. (Is this another adapter?)
Suppose, for example, I have an abstract collection of objects called Coll and I want an iterator to be able to run through the collection.
Now your iterator would probably have a pointer to Coll and some either item relating to its current position. In order to get to the data, or to advance, your iterator would have to consult Coll and pass it the positioning data too.
You must consider the fact that the positioning data itself could be dependent on the implementation of Coll, and therefore consider that you actually have an abstract class, let's call it Pos. We can now use this abstract class Pos to iterate through our data.
But what about our iterator? Easy - our iterator will have a shared-pointer to a Pos and will use this Pos to access data and to increment itself, and to compare itself to another Pos. But iterator itself (which is going to be cloned) is now a concrete class.
The idea would be similar comparison to using an std::string.
A function that does NOT need a local modifiable copy of a std::string can have the following signature:
void func(const std::string &);
In cases like this, the function will do just fine with the source copy of the string.
Similar logic with the lazy_ptr
void func(const lazy_ptr<foo>&);
So in above code, we expect that the using code doesn't need a local modifiable copy of the pointer.
If you have a function that needs a local copy of the string (and not original), then you would have a signature like this:
void func(std::string src);
If you need a local copy of the string which you want to modify, you gain no benifit by having a constant reference argument.
One nice thing about a reference string, is that if you pass by value, it does not create a new string, and instead references the source string.
So if your function only needs to modify the input arguments under certain conditions, you can still gain the benifit of not having to create a completely new string object if the condition is false.
Similar logic could be apply to a lazy_ptr.
void func(lazy_ptr<foo> src);
The above function is passing by value, but a new foo object is not create until non-constant access is made.
So you could have some conditional logic that if false, would not require modification of the src object, and therefore it would not require a new object to be created.
Hence the name, lazy pointer, since it only recreates the object when needed, and not absolutely.
The point is to try and duplicate the logic you would use in a string reference counter.