Search code examples
c++containers

How to properly implement the changing of an element in a container class?


I am building a container type which holds pointers to a class heirachy. My issue is that I can't seem to change an element using something like:

container[0] = x

Here's a minimal example that reproduces my problem.

#include <iostream>
#include <vector>
#include <memory>

using namespace std;


class Animal {

protected:
    std::string noise = "None";
public:
    Animal() = default;

    virtual ~Animal() = default;

    virtual std::string getNoise() {
        return noise;
    }

};

class Duck : public Animal {
public:
    Duck() {
        noise = "Quack!";
    }
};


class Dog : public Animal {
public:
    Dog() {
        noise = "Bark!";
    }
};

class Cat : public Animal {
public:
    Cat() {
        noise = "Me-thefuck-ow!";
    }

    Cat& operator=(Cat const& other) {
        noise = other.noise;
        return *this;
    }
};

typedef std::shared_ptr<Animal> AnimalPtr;


class AnimalsContainer {
public:
    std::vector<AnimalPtr> animals;
    AnimalPtr front;
    Duck duck;
    Dog dog;

    AnimalsContainer() {
        animals.push_back(std::make_unique<Animal>(duck));
        animals.push_back(std::make_unique<Animal>(dog));
        front = animals[0];
    }
    AnimalsContainer(AnimalsContainer& animalsContainer) = default;
    ~AnimalsContainer() = default;
    AnimalsContainer& operator=(const AnimalsContainer&  animalsContainer) = default;
    AnimalsContainer& operator=(AnimalsContainer&& animalsContainer) = default;

    AnimalPtr operator[](int index){
        return animals[index];
    }
};


int main() {
    AnimalsContainer animalsContainer;

    cout << animalsContainer[0]->getNoise() << endl;

    Cat cat;
    animalsContainer[0] = std::make_unique<Animal>(cat);

    cout << animalsContainer[0]->getNoise() << endl;
    return 0;
}

This outputs:

Quack!
Quack!

Where I want:

Quack!
Meow!

Solution

  • Here:

    AnimalPtr operator[](int index) {
        return animals[index];
    }
    

    You return by value, then the copy is assigned a new value. You are supposed to return a reference:

    AnimalPtr& operator[](int index) {
        return animals[index];
    }
    

    Also you probably meant to use make_shared instead of make_unique in all cases.