Имеет ли значение, какой элемент я удаляю в объединении - PullRequest
0 голосов
/ 18 января 2020

Я пишу переводчик и для этого я хочу создать класс Глагол. этот класс должен сохранять полное cunjugation только тогда, когда он нерегулярный, потому что он будет создавать большие списки, занимая много памяти. Итак, вот мой код:

#include "string.h"  

struct Irregular{
    std::string present;  
    std::string simplepast;  
    std::string pastparticiple;  
}  

union Verbform{  
    Irregular* irregular;  
    std::string* regular;  
    Verbform(Irregular irreg){irregular=new Irregular(irreg);}  
    Verbform(std::string s){regular=new std::string(s);  
    ~Verbbform(){delete regular;}  //here is my problem  
}  

class Verb{  
    public:  
        //some public functions  
    private:  
        Verbform verbform;  
        //some other things;
}  

Когда я делаю это таким образом и инициализирую его неправильным глаголом, удаляет ли он полный неправильный глагол или только первую строку?

Когда я делаю это следующим образом: ~Verbform(){delete irregular;} и я инициализирую его нормальной строкой, удаляет ли он больше, чем я хочу, чтобы он удалил?

1 Ответ

5 голосов
/ 18 января 2020

delete irregular вызывает деструктор ~Irregular(), который затем вызывает деструктор std::string::~string() 3 раза. Вызов этого, когда irregular не является активным членом объединения, неопределенное поведение .

delete regular вызывает деструктор std::string::~string() 1 раз. Вызов этого, когда regular не является активным членом объединения, является неопределенным поведением .

Вам необходимо отслеживать, какой член объединения активен, чтобы вы могли вызвать соответствующий деструктор, например :

enum Verbform_type { vtIrregular, vtRegular };

union Verbform_data {
    Irregular* irregular;
    std::string* regular;
};

struct Verbform {
    Verbform_type type;
    Verbform_data data;

    Verbform(Irregular irreg) {
        type = vtIrregular;
        data.irregular = new Irregular(irreg);
    }

    Verbform(std::string reg) {
        type = vtRegular;
        data.regular = new std::string(reg);
    }

    ~Verbform() {
        switch (type) {
            case vtIrregular:
                delete data.irregular;
                break;
            case vtRegular:
                delete data.regular;
                break;
        }
    }
} 

Кроме того, не забывайте следовать правилу 3/5/0 , добавляя конструкторы копирования / перемещения и операторы копирования / перемещения.

В противном случае вам следует просто полностью избавиться от структуры Verbform и использовать вместо нее std::variant. Пусть он обрабатывает все эти детали для вас.

using Verbform = std::variant<Irregular, std::string>;
...