Composition using reference or pointer? - c++

Please let me know which one is good
Consider I have a class like this
class Shape
{
public:
virtual void Display()
{
cout << "Shape::Display()" << endl;
}
};
class Line : public Shape
{
public:
void Display()
{
cout << "Line::Display()" << endl;
}
};
class Circle : public Shape
{
public:
void Display()
{
cout << "Circle::Display()" << endl;
}
};
1)
class Container
{
public:
Container(Shape& shape) : m_Shape(shape)
{
}
void Draw()
{
m_Shape.Display();
}
private:
Shape& m_Shape;
};
Here he is taking reference and assigning it to the base class object.
2)
class ShapeContainer
{
public:
ShapeContainer(Shape* pShape) : m_pShape(pShape)
{
}
void Draw()
{
m_pShape->Display();
}
private:
Shape* m_pShape;
};
Here he is taking the pointer and assigning it to the base class object.
Please let me know which one is good or when to use them

The decision has to be taken in terms of what you want to do with your object. Since you are not including the option of storing a value, I will assume that you need the container to refer to an external object. If this is not a requirement, consider using what standard containers do: store a copy of the object.
By using a reference you avoid having to check for NULL on creation (after creation both solutions share the same problem there: the external object might be destroyed, leaving you with a dangling reference and Undefined Behavior). The semantics of a reference are a little stronger, and anyone that reads the code will immediately understand: This container is meant to hold a reference to this object for the whole lifetime of the container, the object lifetime is managed externally.
On the negative side of it, references are not resettable, once you set a reference it becomes an alias to the object, and you cannot reset it to refer to a different object. This means that a container that holds a reference will not be assignable by default as you cannot make it refer to a different object. Even if you provide a custom assignment operator, the reference cannot be changed and it will keep referring to the old object. You will not be able to provide member functions in the container to refer to a different object: once you set a reference, it is set forever.
Pointers on the other hand, can be NULL, so you might want/need to check for validity of the pointer before use. They are resettable, and you can offer operations to have your container refer to a different object at any point, by default the container will be assignable. On the negative side, pointers can be used in different scenarios, so the semantics are not so clear. In particular, you will have to carefully document on the interface whether the container takes ownership of the pointer (and the responsibility to release the memory) or not. If you are going to handle ownership inside the container, then consider using a smart pointer (or else just make a copy and forget the original if you can, which will be less error prone).

I perosnally prefer using references over pointers whenever possible. This avoids having to do a NULL check before using the pointer as references can not be NULL. BTW, your shape class requires a virtual destructor.

I'd rather say that there is no good or bad in this case, it's just a matter of what you want to do.
If the user is not allowed to store NULL pointers in your vector because it's a requirement, then use by reference. But if the user wants to reserve space for 10 objects but only wishes to have the first 3 initialized, then you'd want to be able to store NULL to be able to differentiate between objects and empty space.
But as said, it's a matter of requirement for the container.
In your case i'd choose by reference.

I would go for the reference approach if there is no need to explicitly control the lifetime of the contained object in the container class and you can be sure that the passed reference object is always valid during the lifetime of the container class.

Related

Reference counting - internal references problem

I have implemented my own smart pointers, and everything worked fine, untill I realized a fatal flaw with my implementation. The problem was the fact that an object can have a smart pointer that potentially holds a reference to itself. the problem would be easy to avoid if this was a one layer problem - what could easly happen is a ref counted class would indirectly (through one of its members) holds a referenece to itself. this would mean that a object would never be removed deleted. Is there any way/method I could solve this?
simplest example:
class Derived : public Object {
public:
static ref<Object> Create() { return ref<Object>(new Derived()); }
private:
Derived() : m_ref(this) // m_ref now holds a reference to Derived instance
{
// SOME CODE HERE
}
ref<Object> m_ref;
};
Object is base class contains reference counter, ref is smart pointer that holds a reference to its assigned object
There is no easy way to handle this issue. It is a fundamental problem with reference counting.
To build intuition as to why this is the case, note that the difficulty of detecting cycles of smart pointers is similar to the difficulty of dealing with the cycles. To detect cycles you need to be able to traverse the pointers from "root pointers". If you could do that, you could mark the ones you see during traversal. If you could mark them you could implement mark-and-sweep, which is garbage collection.

C++: Replace object in std::vector 'in place' with a new object of same type but keep references to this object

is it possible to replace an object in a std::vector with another object of same type and maintain any references to this object which was just replaced?
Let's say we have a
std::vector<MyObj> objs
and I want to replace an MyObj-object such that all references to this MyObj are still intact - is this possible?
You cannot do it in general without some serious misuse of the language (e.g. using placement new in a situation for which it has not been designed). However, you can design MyObj class in a way that makes implementing this use case very straightforward. For example, if MyObj follows the Envelope and Letter Idiom which puts the implementation (the letter) and its wrapper (the envelope) into separate classes, you could make an array of wrappers, and replace their inner content without disturbing outside references:
// The real functionality goes here
struct MyObjImpl {
void operation1() { ... }
void operation2() { ... }
};
// This is a wrapper that forwards calls to the implementation,
// which can be switched at any time without disturbing references to MyObj
class MyObj {
MyObjImpl* wrapped;
public:
MyObj(MyObjImpl* rep) : wrapped(rep) {}
void switch(MyObjectImpl* rep) {
wrapped = rep;
}
void operation1() { wrapped->operation1(); }
void operation2() { wrapped->operation2(); }
};
Assuming that the only way to "replace" an object is to assign to it, then it is in fact unlikely that any references to the assigned-to object are invalidated in the first place.
That is, the answer is: You do not have to do anything special. All references to the "replaced" object remain intact.
Of course, there are other reasons that references to an object held in a std::vector are invalidated, but they do not happen during a well-behaved assignment to the object being held.
Maybe you will want to save states of replaced objects via memento pattern as it's called or just a save state control object. Ref to memento from wiki https://en.wikipedia.org/wiki/Memento_pattern as it's lacking C++ implementation it's simple to write. Also you may want to keep track of replaced objects so might extend it a bit.

Is it a good practice to make a method which modifies data outside the class const?

I would like to ask a question about methods' const-correctness. Let me illustrate the situation.
class MyClass
{
public:
...
void DiscussedMethod() { otherClass->NonConstMethod(); }
private:
OtherClass *otherClass;
};
I have a class MyClass which keeps a pointer to OtherClass. In DiscussedMethod it calls OtherClass::NonConstMethod which modifies some visible data.
I would like to know, whether it would be a good practice to make the DiscussedMethod const (since it doesn't modify any member data)? Would it be a bad practice? Or is both fine?
What if the OtherClass kept a pointer to the MyClass and in NonConstMethod modified some of the MyClass' data (meaning that the MyClass member data would change during the DiscussedMethod call). Would it be a bad practice to make the DiscussedMethod const then?
As far as I've been able to find out, the const on a method is mostly a code documenting thing, so I would probably lean toward to not making the DiscussedMethod const, but I would like to hear your opinions.
EDIT: Some replies take the into account whether the object pointed to by otherClass is owned by the MyClass object. This is not the case in the scenario I'm working with. Lets say that both objects exist independently side by side (with the ability to modify each other). I think this analogy describes my situation quite well.
For example consider something like doubly-linked list, where each element is a class that keeps pointer to its neighbours and member variable color. And it has method MakeNeighboursRed which changes the color of its neighbours but doesn't affect the calling object's state itself. Should I consider making this method const?
And what if there was some possibility that MakeNeighboursRed would call neighbour's MakeNeighboursRed. So in the end the state of the object for which MakeNeighboursRed has been called originally would change as well.
And I would like to thank you all for your opinions :-)
If MyClass owns the OtherClass instance i wouldn't make DiscussedMethod constant.
The same goes for classes, managing resources. I.e. the standard containers do not return non const references or pointers to the managed memory using const functions, although it would be "possible" (since the actual pointer holding the resource is not modified).
Consider
class MyClass
{
public:
bool a() const { return otherClass->SomeMethod(); }
void b() const { otherClass->NonConstMethod(); }
private:
OtherClass *otherClass;
};
void foo (MyClass const &x)
{
cout << boolalpha << x.a() << endl;
x.b(); // possible if b is a const function
cout << boolalpha << x.a() << endl;
}
The foo could print two different values although an implementor of foo would probably expect that two function calls on a const object will have the same behaviour.
For clarification:
The following is invalid according to the standard since the const version of operator[] returns std::vector<T>::const_reference which is a constant reference to the value type.
std::vector<int> const a = { /* ... */ };
a[0] = 23; // impossible, the content is part of the state of a
It would be possible if there was only one signature of this function, namely referece operator[] (size_t i) const;, since the operation does not alter the internal pointers of the vector but the memory they point to.
But the memory, managed by the vector is considered to be part of the vectors state and thus modification is impossible through the const vector interface.
If the vector contains pointers, those pointer will still be unmodifiable through the public const vector interface, although the pointers stored in the vector may well be non const and it may well be possible to alter the memory they point to.
std::vector<int*> const b = { /* ... */ };
int x(2);
b[0] = &x; // impossible, b is const
*b[0] = x; // possible since value_type is int* not int const *
In OOP object should be fully described by its state, available through its interface. Thus, const methods should not alter object's state, if these changes might be observed through the interface.
A good example is a mutable mutex inside your class to guard some shared resources. It might be modified from const method, since it does not introduce any changes observable via class interface.
General rule of thumb is, that if you can make a member function const, you probably should. The reason for that is that it allows you to catch unintended behaviour and bug easier.
Another argument in favor would be that if you have this function as const you are allowed to call it on const object, so it isn't really a documentation thing.
Overall it depends what the other class is. It's not black and white...
If otherClass is a log object (for example) and you want to log the operation of the current object then it's perfectly fine calling it from a const function.
If the otherClass is a container that for design (or implementation) purposes is implemented as a separate object than effectively a const function modifies the object making this a very bad idea.
I hope this helps.
It's totaly incorrect to make DiscussedMethod const as it changes it's *this state. The only loophole to this is making non-logically-part-of-object's-state member data mutable so they can be changed in const functions. This would be things like a member that hold a count for "number of times function x() has been called". Any thing else is part of the object's state, and if a function changes it (at any level), that function isn't const.
I would like to know, whether it would be a good practice to make the DiscussedMethod const (since it doesn't modify any member data)?
otherClass is member data, and it (or rather, the object it points to) gets modified.
Consider the semantics should the pointer to otherClass be refactored to a fully-owned object... whether something is held as a pointer, reference, or object doesn't change the semantical ownership, IMO.

unique_ptr and polymorphism

I have some code that currently uses raw pointers, and I want to change to smart pointers. This helps cleanup the code in various ways. Anyway, I have factory methods that return objects and its the caller's responsibility to manager them. Ownership isn't shared and so I figure unique_ptr would be suitable. The objects I return generally all derive from a single base class, Object.
For example,
class Object { ... };
class Number : public Object { ... };
class String : public Object { ... };
std::unique_ptr<Number> State::NewNumber(double value)
{
return std::unique_ptr<Number>(new Number(this, value));
}
std::unique_ptr<String> State::NewString(const char* value)
{
return std::unique_ptr<String>(new String(this, value));
}
The objects returned quite often need to be passed to another function, which operates on objects of type Object (the base class). Without any smart pointers the code is like this.
void Push(const Object* object) { ... } // push simply pushes the value contained by object onto a stack, which makes a copy of the value
Number* number = NewNumber(5);
Push(number);
When converting this code to use unique_ptrs I've run into issues with polymorphism. Initially I decided to simply change the definition of Push to use unique_ptrs too, but this generates compile errors when trying to use derived types. I could allocate objects as the base type, like
std::unique_ptr<Object> number = NewNumber(5);
and pass those to Push - which of course works. However I often need to call methods on the derived type. In the end I decided to make Push operate on a pointer to the object stored by the unique_ptr.
void Push(const Object* object) { ... }
std::unique_ptr<Object> number = NewNumber(5);
Push(number.get());
Now, to the reason for posting. I'm wanting to know if this is the normal way to solve the problem I had? Is it better to have Push operate on the unique_ptr vs the object itself? If so how does one solve the polymorphism issues? I would assume that simply casting the ptrs wouldn't work. Is it common to need to get the underlying pointer from a smart pointer?
Thanks, sorry if the question isn't clear (just let me know).
edit: I think my Push function was a bit ambiguous. It makes a copy of the underlying value and doesn't actually modify, nor store, the input object.
Initially I decided to simply change the definition of Push to use
unique_ptrs too, but this generates compile errors when trying to use
derived types.
You likely did not correctly deal with uniqueness.
void push(std::unique_ptr<int>);
int main() {
std::unique_ptr<int> i;
push(i); // Illegal: tries to copy i.
}
If this compiled, it would trivially break the invariant of unique_ptr, that only one unique_ptr owns an object, because both i and the local argument in push would own that int, so it is illegal. unique_ptr is move only, it's not copyable. It has nothing to do with derived to base conversion, which unique_ptr handles completely correctly.
If push owns the object, then use std::move to move it there. If it doesn't, then use a raw pointer or reference, because that's what you use for a non-owning alias.
Well, if your functions operate on the (pointed to) object itself and don't need its address, neither take any ownership, and, as I guess, always need a valid object (fail when passed a nullptr), why do they take pointers at all?
Do it properly and make them take references:
void Push(const Object& object) { ... }
Then the calling code looks exactly the same for raw and smart pointers:
auto number = NewNumber(5);
Push(*number);
EDIT: But of course no matter if using references or pointers, don't make Push take a std::unique_ptr if it doesn't take ownership of the passed object (which would make it steal the ownership from the passed pointer). Or in general don't use owning pointers when the pointed to object is not to be owned, std::shared_ptr isn't anything different in this regard and is as worse a choice as a std::unique_ptr for Push's parameter if there is no ownership to be taken by Push.
If Push does not take owenrship, it should probably take reference instead of pointer. And most probably a const one. So you'll have
Push(*number);
Now that's obviously only valid if Push isn't going to keep the pointer anywhere past it's return. If it does I suspect you should try to rethink the ownership first.
Here's a polymorphism example using unique pointer:
vector<unique_ptr<ICreature>> creatures;
creatures.emplace_back(new Human);
creatures.emplace_back(new Fish);
unique_ptr<vector<string>> pLog(new vector<string>());
for each (auto& creature in creatures)
{
auto state = creature->Move(*pLog);
}

Inheritance / Polymorphism - calling method of subclass

In the following, how can I make it such that the program uses the draw method from MainMenuScreen instead of the one from GameScreen?
class GameScreen {
public:
virtual void GameScreen::draw() {
cout << "Drawing the wrong one..." << endl;
}
};
class MainMenuScreen : public GameScreen {
public:
void MainMenuScreen::draw() {
cout << "Drawing the right one..." << endl;
}
};
class ScreenManager {
public:
list<GameScreen> screens;
// assume a MainMenuScreen gets added to the list
void ScreenManager::draw()
{
for ( list<GameScreen>::iterator screen = screens.begin();
screen != screens.end(); screen++ )
{
screen->draw(); /* here it uses the draw method from GameScreen,
but I want it to use the draw method from
MainMenuScreen */
}
}
};
PS: I do not want to make GameScreen::draw purely virtual, so please suggest something else.
how can I make it such that the program uses the draw method from
MainMenuScreen instead of the one from GameScreen?
You can't, unless you call it on a pointer or reference whose actual type is MainMenuScreen.
list<GameScreen> screens;
declares a list of objects, not pointers or references. If you add MainMenuScreen objects to it, they will lose type information because of object slicing and polymorphism will not work. You need:
list<GameScreen*> screens;
or, better yet:
list<shared_ptr<GameScreen> > screens;
You don't want to make draw pure virtual, but you do want to make it (or keep it) virtual. To go with that, you want to make screens a list of pointers (or possibly smart pointers of some sort) to GameScreens rather than a list of GameScreen objects.
As it is right now, when you (attempt to) insert your MainMenuScreen object into the list, it's being "sliced" to actually become a GameScreen object -- therefore, when you walk your list, you're walking a list of objects whose actual types are all GameScreen; hoping to get MainMenuScreen behavior from any of them at that point is futile.
With a list of pointers, a MainMenuScreen will remain exactly that, so when you invoke your virtual function, you'll get the behavior of the actual type.
You've fallen victim to object slicing. The objects in your list are only copies of the objects you inserted into it, and as each copy was made it got demoted to the contained type.
The way around this is to insert pointers (preferably smart pointers such as shared_ptr) into the list.