0

So I have std::list of a class and I add objects of its derived classes(e.g. "Discus" is a derived class of "Item"). I have several std::string variables and I initialize it in constructor. That std::string variables are gotten via std::cin, I put such variables right into a constructor. E.g. 'name' and 'material', that's gotten via std::cin, it's just std::string. So it has some values. But when I go out of that function, its values are empty(it's like ""). What can cause this problem? I suppose that 'name' and 'material' variables are being deleted, but I'm not sure if it's true and how to get rid of this problem. Sorry if this question is kinda silly, thanks for any help.

class Discus : public Throwable, public Material {
public:
    Discus(int, int, int, std::string*, std::string*);
    void setMaterial(std::string*);
    void setType();
    std::string info();
};

class Storage {
private:
    std::list<Item*> storage;
public:
    std::list<Item*>* getStorage();
    void addItem(Item*);
    void showInfo();
};

That's the implementation of a function I use to add Items:

void addItem(Storage* store) {
bool to_continue = true;
while (to_continue) {
    std::cout << "What to add?\n1)Discus\n2)Javelin\n3)Hammer\n4)Dumbbell\n5)Kettlebell\n6)Barbell\0 для to exit\n";
    int key = -1;
    std::cin >> key;
    if (key > 0 && key < 7) {
        int parameters[3];
        std::cout << "Enter price, amount of items, the weight of an item\n";
        for (int i = 0; i < 3; i++) std::cin >> parameters[i];
        std::string name;
        std::string material;
        int len = 0;
        std::cout << "Enter name:\n";
        std::cin >> name;
        switch (key) {
        case 1: {
            std::cout << "Enter a name of material:\n";
            std::cin >> material;
            Discus d(parameters[0], parameters[1], parameters[2], &material, &name);
            Discus* it = &d;
            (*store).addItem(it);
            break;  
        }
        case 2: {
            std::cout << "Enter a name of material:\n";
            std::cin >> material;
            std::cout << "Enter a length:\n";
            std::cin >> len;
            (*store).getStorage()->push_back(&Javelin(parameters[0], parameters[1], parameters[2], &material, len, &name));
            break; 
        }
        case 3: {
            std::cout << "Enter a name of material:\n";
            std::cin >> material;
            std::cout << "Enter a length:\n";
            std::cin >> len;
            (*store).getStorage()->push_back(&Hammer(parameters[0], parameters[1], parameters[2], &material, len, &name));
            break;
        }
        case 4:
        {(*store).getStorage()->push_back(&Dumbbell(parameters[0], parameters[1], parameters[2], &name)); break; }
        case 5: {
            std::cout << "Enter a name of material:\n";
            std::cin >> material;
            (*store).getStorage()->push_back(&Kettlebell(parameters[0], parameters[1], parameters[2], &material, &name));
            break;
        }
        case 6: {
            std::cout << "Enter a length:\n";
            std::cin >> len;
            (*store).getStorage()->push_back(&Barbell(parameters[0], parameters[1], parameters[2], len, &name));
            break;
        }
        }
    }
    else if (key == 0) 
        to_continue = false;
    else std::cout << "Sorry, try one more time\n";
}
}
Paul Snopov
  • 205
  • 1
  • 9
  • 1
    Why do you want to use pointers? What is your requirement? – Kunal Puri Jan 13 '19 at 13:44
  • Also, Please give more info on the part of code in which object `d` is created. – Kunal Puri Jan 13 '19 at 13:45
  • `void setMaterial(std::string*);` its strange to use `std::string*` – drescherjm Jan 13 '19 at 13:48
  • 3
    `&d` is an invalid pointer as soon as `d`’s lifetime ends. (There are far too many pointers in this code. Consider thinking it over a few more times.) – molbdnilo Jan 13 '19 at 13:49
  • added function that add Items. – Paul Snopov Jan 13 '19 at 13:52
  • @molbdnilo is correct. There should be a few duplicates for this. – drescherjm Jan 13 '19 at 13:52
  • Possible duplicate of [Can a local variable's memory be accessed outside its scope?](https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope) – drescherjm Jan 13 '19 at 13:53
  • 1
    Note that all of the `(*store).getStorage()->push_back(&Javelin ...` and similar calls are wrong as well for the same reason (you are taking the address of a temporary). My advice is to not use pointers for any of this. – drescherjm Jan 13 '19 at 14:00
  • 2
    I think one must never use raw pointers unless there is necessity to do so. One should always look for smart pointers. If they don't suffice, then one should think twice before using raw pointers. – Kunal Puri Jan 13 '19 at 14:07

1 Answers1

0

The main reason behind this is that the object might be dying when it is going out of scope.

It seems your situation is somewhat like this:

...
    if (key > 0 && key < 7) {
        ...
        std::string name;
        std::string material;
        ...
        switch (key) {
        case 1: {
            ...
            Discus d(parameters[0], parameters[1], parameters[2], &material, &name);
            Discus* it = &d;
            (*store).addItem(it);
            break;  
        } // d will die here. So, pointer it will become dangling
    } // name and material will die here. So, pointers to them will become dangling.

You may consider using const std::string & for your purpose instead of std::string *. For object of class Discus, instead of using raw pointer, you may go for unique_ptr.

Kunal Puri
  • 3,419
  • 1
  • 10
  • 22