How the array of std::shared_ptr in C++ works - c++

I am a c++ beginner and learning about smart pointers and inheritance. I have a base class Shape(abstract) and as derived classes I have Triangle, Isosceles and Equilateral.
My idea is to print appropriate print message for each class according to the type which is pointed the base class, which I have declared in the main() as shown below.
#include <iostream>
#include <memory>
class Shape
{
public:
virtual const void triangle()const = 0;
virtual ~Shape(){ std::cout<<"Shape Deleted\n"; }
};
class Triangle: public Shape
{
public:
virtual const void triangle()const override
{ std::cout<<"I am a triangle\n"; }
virtual ~Triangle(){ std::cout<<"Triangle Deleted\n"; }
};
class Isosceles : public Triangle
{
public:
virtual const void triangle()const override
{ std::cout<<"I am an isosceles triangle\n"; }
virtual ~Isosceles(){ std::cout<<"Isosceles Deleted\n"; }
};
class Equilateral: public Isosceles
{
public:
virtual const void triangle()const override
{ std::cout<<"I am an equilateral triangle\n"; }
virtual ~Equilateral(){ std::cout<<"Equilateral Deleted\n"; }
};
When I use traditional way of creating a pointer object using new key word, the distructors of all classes works perfectly(out put is given below).
The main() was:
int main()
{
Shape *Obj[3];
Obj[0] = new Equilateral();
Obj[1] = new Isosceles();
Obj[2] = new Triangle();
for(auto it: Obj)
it->triangle();
delete Obj[0];
return 0;
}
The output is here
But when I change to std::shared_ptr things are different which I could not understand.
The main() was:
int main()
{
std::shared_ptr<Shape> obj[3];
obj[0] = std::make_shared<Equilateral>();
obj[1] = std::make_shared<Isosceles>();
obj[2] = std::make_shared<Triangle>();
for(auto it: obj)
it->triangle();
return 0;
}
The Output Now:
Can anybody help me figure it out, why this happens?
may thanks in advance.

When you use raw pointers you only destroy the first object:
delete Obj[0];
and make other 2 leak, while when you use std::shared_ptr all 3 objects cleaned properly. This is exact reason why using smart pointers is recommended practice.

Actually your second snippet is correct and the output is exactly as expected.
Your first snippet has a bug: you just delete obj[0];. What about obj[1] and obj[2]? If you delete all members of the array, you'll see that the difference between the outputs of two code samples vanish.
The good thing about smart pointers is that they are supposed to be used in a "fire-and-forget" manor.
Finally, read that book of yours with greater caution: you need to master the order of construction and destruction before starting anything about OOP.

Related

Objects and composition of objects

I'm coming from c#/Java/TypeScript. So do I initialise objects inside a class. For example for a chess game. Lets say I have class for the spot on the board, the board.
So normally it will be
public class Piece()
{
bool isWhite;
Piece(isWhite){
this.isWhite = true;
}
}
public class Spot(){
Piece piece //Chess Piece
Spot(bool isWhite)
{
this.piece.isWhite = isWhite;
}
}
As mentioned in the comment to your post https://cppreference.com/ is usually the best place to look up documentation.
Now about your question:
#include <iostream>
#include <vector>
class Piece
{
public:
~Piece() = default;
explicit Piece(bool isWhite)
{
this->isWhite = isWhite;
}
bool isWhite;
};
class Board
{
public:
Board() = default;
~Board() = default;
void addPiece(Piece p)
{
pieces.push_back(p);
}
std::vector<Piece> pieces;
};
int main()
{
Board b;
Piece p(true);
b.addPiece(p);
std::cout << "Hello World!\n";
return 0;
}
This is how you would usually define a class that has a member from another class.
You should definitely check out constructors and destructors in c++ as they are very important (https://www.tutorialspoint.com/cplusplus/cpp_constructor_destructor.htm).
And as for vector, this is a generic container from the c++ standard library.
Edit: I did indeed forget to add the default keyword to the constructor and destructor of Board which are unnecessary. The reason I've left them there is to showcase their existence to someone new to the language.
Also the reason I didn't pass the piece be reference is because references and pointers might be a complete chapter for someone new to the language.
Basically, the optimal way to write:
void addPiece(Piece p)
{
pieces.push_back(p);
}
is:
void addPiece(const Piece& p)
{
pieces.push_back(p);
}

How to properly deep copy 2D array of abstract class array in C++ with C style

I have abstract class Figure. Then I have an array of it, and I want to resize it, but not sure how to do it.
Figure ** arr; //lets assume it's filled with some data
Figure ** temp = new Figure * [size + 1];
for(int i =0; i < size; ++i)
{
temp[i] = new Figure(); //it doesn't let me to create object from the abstract class
temp[i] = arr[i] //if I do this, once I delete arr, I will lose temp as well
}
Any help?
The problem
If Figure is an abstract class, you can't instantiate it:
temp[i] = new Figure(); // ouch: can't do: strictly forbidden
and even if you could, you couldn't copy such a polymorphic class without suffering from slicing:
temp[i] = arr[i]; // arr[i] is a derivate of Figure and might have a different size for example
The solution
To solve your issue, you must define a virtual clone() member function:
class Figure {
...
Figure* clone() = 0;
};
You would then implement this function, for example like this:
class Square : public Figure {
...
Figure* clone() override {
return new Square(*this);
}
};
You would change your deep copy to to:
temp[i] = arr[i].clone();
The improvement
The risk of returning a freshly allocated clone is to have a memory leak. So
instead of using raw pointers you could use shared_ptr<Figure> or unique_ptr<Figure> (not only as return argument of the cloning function but also as element of the array.
By the way, you could also consider changing the array to a vector, thus avoiding extra manual memory allocation (and later deletion) of the temp.
The answer is to take advantage of the polymorphic behavior the class hierarchy provides and make a virtual function to create the copy. For example, clone is a commonly named function for this.
Example Code
#include <iostream>
#include <memory>
#include <vector>
class Base
{
public:
virtual ~Base() {}
virtual Base* clone() const = 0;
virtual void print() const = 0;
};
class D1 : public Base
{
public:
virtual D1* clone() const override { return new D1(*this); }
virtual void print() const override { std::cout << "D1\n"; }
};
class D2 : public Base
{
public:
virtual D2* clone() const override { return new D2(*this); }
virtual void print() const override { std::cout << "D2\n"; }
};
int main()
{
std::vector<std::unique_ptr<Base>> original;
original.push_back(std::make_unique<D1>());
original.push_back(std::make_unique<D2>());
std::vector<std::unique_ptr<Base>> copy;
for (const auto& o : original)
{
copy.push_back(std::unique_ptr<Base>(o->clone()));
}
for (const auto& c : copy)
{
c->print();
}
return 0;
}
Example Output
D1
D2
Live Example
All of this can be achieved just the same with C style arrays however this question is tagged with C++.
Note: Even though the derived classes have a different signature for their respective clone functions this is perfectly valid. See covariant return type for more information.

Best method to implement an abstract factory pattern

Consider following code:
#include <stdio.h>
// =============================
class Shape{
public:
virtual ~Shape(){};
virtual void process() = 0;
};
class Triangle : public Shape{
public:
virtual void process() override {
printf("BBB\n");
}
};
// =============================
/* option 1 */
class TriangleProducer{
public:
Triangle factory(){
return Triangle {};
}
};
/* option 2 */
class PtrShapeProducer{
public:
Shape *factory(){
return new Triangle {};
}
};
/* option 3 */
class PimplShape : public Shape{
Shape *sh;
public:
PimplShape(Shape *sh) : sh(sh){
}
virtual ~PimplShape() override{
delete sh;
}
virtual void process() override {
sh->process();
}
};
class PimplShapeProducer{
public:
PimplShape factory(){
return new Triangle {};
}
};
// =============================
int main(){
TriangleProducer f1;
Triangle tri = f1.factory();
tri.process();
PtrShapeProducer f2;
Shape & sh = *f2.factory();
sh.process();
delete & sh;
PtrShapeProducer f3;
PimplShape psh = f3.factory();
psh.process();
return 0;
}
OPTION 1
It is nice, but it does not really achieve polymorphism. Return type is known and you must match it. One may add auto instead of Triangle, but this not change anything except easier refactoring.
OPTION 2
This is how Java and PHP is doing it. But I understood that "raw" pointers are not desirable in C++. One may add std::unique_ptr, but once again this does not change anything, except missing delete statement.
OPTION 3
This is what someone propose here some time ago - works nice, no "raw" pointers, no delete. But it is so much code, and way too complicated - seems fancy way, but not the correct one.
OPTION 4 (not implemented here)
Playing with const references - however they are const and it does not change the "factory" return type. I think, this is more like variation, it is not real option.
Any other option I am missing?
Also what would be best option to go?
I think the most idiomatic modern C++ method is the one you mention in passing but ignore. Return a std::unique_ptr<Shape>.
It is safe, clearly expresses ownership, supports polymorphism and doesn't need much code.
class ShapeFactory {
public:
std::unique_ptr<Shape> create(){
return std::make_unique<Triangle>();
}
};
But I wouldn't want to claim it was the "best" method.
Your PimplShape in option 3 is actually very similar to a unique_ptr just less generic or tested.
Your factories are passing around ownership. There's another alternative to that aspect; instead of passing around ownership, you can make the factory own the objects:
class Factory {
public:
~Factory() { for(int i=0;i<vec.size();i++) delete vec[i]; }
Shape &build_obj() {
Shape *sh = new Triangle;
vec.push_back(sh);
return *sh;
}
private:
void operator=(const Factory &);
std::vector<Shape*> vec;
};

How can I insert a Parent* object (which points to an &Child object), into a vector<Child>? [duplicate]

This question already has answers here:
What is object slicing?
(18 answers)
Closed 8 years ago.
I've provided an extremely simplified version of the code which reproduces the error.
class Shape {
public:
virtual void func()=0;
};
class Circle : public Shape {
public:
Circle() { }
void func() { }
};
class Square : public Shape {
public:
Square() { }
void func() { }
};
int main() {
Circle c;
std::vector<Circle> circs;
std::vector<Shape*> shapes;
shapes.push_back(&c);
circs.push_back(shapes[0]); //ie, the Circle object that was just pushed into the 'shapes' vector.
}
I know that as of right now, this is functionally useless, and that I could just push the Circle object to the vector - however, in keeping with the shape analogy, my project also has triangles, squares, etc. I process data using a function which accepts Shape& as a parameter, so that I can send all shapes to one function, instead of separate functions for each shape. That's besides the point, but gives insight into why I'm doing what I'm doing in the simplified code.
The last line in this code will not work. Could anyone tell me why? Or provide me with a solution/work-around? Is this considered bad programming-style?
EDIT: So I've solved the Object Slicing issue I was having. For anyone with the same issue, look at fgp's answer in the following thread:
What is object slicing?
I used the following to help allow what I was trying to do (Move a Circle object to a Shape*, compute some things, then push the Circle (which is in the Shape* vector), to its final resting place, a Circle vector:
class Shape {
public:
virtual Shape& operator=(const Shape& s) {
assign(s);
return *this;
}
virtual std::string getName() = 0;
virtual int getEdges() = 0;
protected:
std::string name;
int edges;
void assign(const Shape& s) {
this->name = s.name;
this->edges = s.edges;
}
};
class Circle : public Shape {
private:
int radius;
public:
Circle() { name = "Circle"; edges = 1; }
Circle(int rad) { name = "Circle"; edges = 1; radius = rad; }
virtual Circle& operator=(const Shape& s) {
if (const Circle* c = dynamic_cast<const Circle*>(&s))
assign(*c);
else{
std::cout << "BAD ASSIGNMENT IN CIRCLE.";
//THROW ERROR HERE INSTEAD OF THE ABOVE COUT
}
return *this;
}
std::string getName() { return name; }
int getEdges() { return edges; }
int getRadius() { return radius; }
void setRadius(int r) { radius = r; }
protected:
void assign(const Circle& c) {
Shape::assign(c);
this->radius = c.radius;
}
};
int main() {
std::vector<Shape*> shapes;
std::vector<Circle> circs;
Circle c2(5); //Creates a circle with 5 for the radius.
shapes.push_back(&c2); //Pushing the 5-radius circle into the Shapes* vector
Circle c3; //Creates a circle with default constructor (which does NOT define radius)
c3 = *shapes[0]; //Now, the overloaded assignment operator. Look at Circle::assign(const Shape&) function
circs.push_back(c3); //We push our newly assigned circle to our Circle vector
std::cout << "c3 radius: " << circs[0].getRadius(); //This will be 5!
}
It was a pleasant surprise to see this work! c3 will now know about c2's radius, showing that the overloaded assignment operators work for a Shape->Circle conversion.
If anyone has some suggestions, please let me know!
(I will be creating a Circle constructor that takes a (const Shape&) param, so I can use Circle c = *shapes[0], instead of having to separate the lines since it cannot find a constructor that accepts that parameter).
EDIT2: Also, if you use this, make sure you throw an error (I left a comment where you should).
This in general is a bad idea to do such things to down cast like you want. However to directly answer the question:
Circle* t = dynamic_cast<Circle*>(shapes[0]);
if(t) //make sure dynamic cast succeeded
circs.push_back(*t);
You have to cast the reference to a Circle type, because it was a Shape.
As I mentioned before, this is not ideal. What you should really do is allow your code to work on polymorphic principles. Use the abstract base class to your advantage! Otherwise this could lead to undefined behavior, especially when shapes probably stores more than just Circles in more realistic code.
Although a class is derived from another one, they're still two different types and thus creating a vector of base objects is different from a vector of derived objects.
As a design point of view (and I strongly reccommend it) you can store a vector of pointers to the base class and let the virtual polymorphism do its job: use a vector of pointers to the base class instead of references.
Edit: since you asked me to expand a bit more on the design concept, this is what I had in mind:
#include <iostream>
#include <vector>
using namespace std;
class Shape {
protected:
Shape() {} // Having a protected constructor only allows you to
// call it from the same or derived class
public:
virtual void func()=0;
};
class Circle : public Shape {
public:
Circle() { }
void func() { cout << "Hello from a Circle object" << endl; }
};
class Square : public Shape {
public:
Square() { }
void func() { cout << "Hello from a Square object" << endl; }
};
int main() {
std::vector<Shape*> shapes;
Circle c;
Square s;
shapes.push_back(&c); // Store the address of the object
shapes.push_back(&s); // Store the address of the object
// A call through a pointer to a virtul polymorphic class
// will make sure to call the appropriate function
shapes[0]->func(); // Hello from a circle object
shapes[1]->func(); // Hello from a square object
}
http://ideone.com/X52GLa
which is an example of runtime polymorphism where you only store a vector of base class pointers. Notice the protected constructor: it prevents you from instantiating Shape objects directly outside of the derived classes.

How to properly use virtual member functions in c++

I am having a problem with the following code, the overriden virtual functions are not executing. Not sure i'm doing wrong here probably a silly mistake. Anyway this is a game project and I have an array of objects which looks like this (the core::array is an irrlicht array, similar to the vector array)
core::array<GameObject> gameTargets;
This is the GameObject and Zombie definition
class GameObject {
protected:
scene::ISceneNode* node;
public:
int ID;
int hitpoints;
GameObject() {
...
};
void setNode(scene::ISceneNode* inode) {
...
}
virtual void shot(int dmg) {
... [BREAKPOINT HERE]
}
scene::ISceneNode* getNode() {
return node;
}
};
class Zombie : public GameObject {
public:
static const enum Animation {
ZOMBIE_WALK,
ZOMBIE_HURT,
ZOMBIE_DIE,
ZOMBIE_TWITCH,
ZOMBIE_ATTACK,
ZOMBIE_IDLE
};
//We only want to accepted animated mesh nodes for this object
Zombie(int hp, scene::IAnimatedMeshSceneNode* inode) {
...
}
//Override the shot function
void shot(int dmg) {
... [BREAKPOINT HERE]
}
//Animate the zombie
void setAnimation(Animation anim) {
...
}
};
The member functions of the derived classes is never called, I am creating the objects like this
Zombie target(hp, (scene::IAnimatedMeshSceneNode*)node);
and calling the virtual function like this
for(int i = 0; (u32)i<level->gameTargets.size(); i++) {
if(selectedNode == level->gameTargets[i].getNode()) {
level->gameTargets[i].shot(b->damage);
}
}
where b is a pointer to a bullet with a int variable damage and gameTargets contains GameObject
I suspect that you're experiencing slicing because the gameTargets array contains values. I can't tell for sure because I don't know how the core::array template works. See What is object slicing? for a discussion about what slicing is.
To fix this problem, store either raw pointers as in
core::array<GameObject *> gameTargets;
Or use some sort of reference-counted pointer like
core::array<std::shared_ptr<GameObject>> gameTargets; // only available in C++11
array<GameObject> is a container of objects, not a container of pointers. Every object you add to it will be a GameObject and not one of the derived classes (if you add a derived class object, then it'll be "sliced").
Without knowing exactly what your core::array does, I suspect what you really intended to create is an array of std::unique_ptr<GameObject> (smart pointers) along the lines of
core::array< std::unique_ptr<GameObject> > gameTargets;
std::unique_ptr<GameObject> my_zombie(new Zombie);
gameTargets.push_back( my_zombie );
a quick solution would be to make those parent functions as pure virtual functions, as in:
virtual void shot(int dmg) { } = 0;
// edit
and use array of pointer as suggested by Frerich Raabe