Почему c ++ преждевременно уничтожает мою строковую переменную? - PullRequest
0 голосов
/ 07 мая 2020

Эта ошибка - одна из самых загадочных, которые я получал за последние годы. Я пробовал что-то взад и вперед часами и не могу этого понять.

В приведенном ниже коде я пытаюсь динамически решить, какой производный класс создать. Я использую параметр функции particle_type, чтобы определить это.

Но поскольку

Particle p;

не допускается, поскольку вам нужно инициализировать ссылки, я пытаюсь сделать это с помощью указатель, как показано ниже.

Particle* p;
if (particle_type == "Featherr") { //This is never called because of the extra "r" I put, so ignore this block
        p = &FeatherParticle(particle_name, position, rotation, velocity, gravityEffect, lifeLength, scale);
}
else {
    p = &Particle(particle_name, position, rotation, velocity, gravityEffect, lifeLength, scale);
}

Particle particle1 = *p;
Particle particle2 = Particle(particle_name, position, rotation, velocity, gravityEffect, lifeLength, scale);

particles.push_back(particle1);
particles.push_back(particle2);

Теперь Particle2 - это просто моя отладка, но он очень хорошо выделяет эту ошибку. Я поставил точку останова на particles.push_back(particle1); и обнаружил, что объект частицы, хранящийся в particle1, был сломан:

enter image description here

Я не понимаю, почему строка здесь установлено значение "". Я могу только догадываться, что это связано с областью видимости, потому что если я установлю строку вне оператора else, она сработает. У меня отвисла челюсть от того, насколько глупая эта функция * и поэтому я думаю, что это может быть ошибка или функциональность, близкая к ошибке.

1 Ответ

3 голосов
/ 07 мая 2020

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

Particle* p;
if (particle_type == "Featherr") { //This is never called because of the extra "r" I put, so ignore this block
    p = new FeatherParticle(particle_name, position, rotation, velocity, gravityEffect, lifeLength, scale);
}
else {
    p = new Particle(particle_name, position, rotation, velocity, gravityEffect, lifeLength, scale);
}
...

Но тогда вы будете нарезать объект при назначении *p на particle1, поэтому используйте вместо этого ссылку (или просто избавьтесь от particle1, так как он вам не нужен):

Particle &particle1 = *p;

Но тогда вы пытаетесь превратить sh Particle объекты в particles , а не Particle* указатели . Так что вы все равно нарежете particle1. Полиморфизм работает только при использовании указателей / ссылок, поэтому вы должны хранить Particle* указателей (что означает использование new для particle2):

std::vector<Particle*> particles;

...

Particle *p;
...
Particle *particle2 = new Particle(particle_name, position, rotation, velocity, gravityEffect, lifeLength, scale);

particles.push_back(p);
particles.push_back(particle2);

И не забудьте delete все, что вы new, когда закончите (и убедитесь, что Particle имеет деструктор virtual):

for(size_t i = 0; i < particles.size(); ++i) {
    delete particles[i];
}

Или, в C ++ 11 и более поздних версиях:

for(auto *p : particles) {
    delete p;
}

Но было бы лучше использовать std::unique_ptr для автоматической обработки этого delete. Используйте std::make_unique() (C ++ 14 и новее), не используйте new напрямую, если можете этого избежать:

std::vector<std::unique_ptr<Particle>> particles;

...

std::unique_ptr<Particle> p;
if (particle_type == "Featherr") { //This is never called because of the extra "r" I put, so ignore this block
    p = std::make_unique<FeatherParticle>(particle_name, position, rotation, velocity, gravityEffect, lifeLength, scale);
    // or:
    // p.reset(new FeatherParticle(particle_name, position, rotation, velocity, gravityEffect, lifeLength, scale));
}
else {
    p = std::make_unique<Particle>(particle_name, position, rotation, velocity, gravityEffect, lifeLength, scale);
    // or:
    // p.reset(new Particle(particle_name, position, rotation, velocity, gravityEffect, lifeLength, scale));
}

auto particle2 = std::make_unique<Particle>(particle_name, position, rotation, velocity, gravityEffect, lifeLength, scale);
// or:
// std::unique_ptr<Particle> particle2(new Particle(particle_name, position, rotation, velocity, gravityEffect, lifeLength, scale));

particles.push_back(std::move(p));
particles.push_back(std::move(particle2));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...