Переменная освобождается после вызова функции - PullRequest
0 голосов
/ 21 октября 2019

Я новичок в C ++ и столкнулся с проблемой. Пожалуйста, смотрите мой код ниже. Эта проблема описана во встроенных комментариях.

#include<iostream>
#include<tuple>
#include<vector>

// #include "test.hpp"

using namespace std;
vector<string*> test();

int main() {
    vector<string*> ret = test();
    cout << ret.back() << endl; //Outputs: Memory of String str
    cout << *ret.back() << endl; //Outputs: random undefined behavior
                                 //I want this to output "s"
}

vector<string*> test() {
    vector<string*> ret;
    string str = "t";
    ret.push_back(&str);
    cout << ret.back() << endl; //Outputs: Memory of String str
    cout << *ret.back() << endl; //Outputs: "t"
    str[0] = 's';
    cout << ret.back() << endl; //Outputs: Memory of String str
    cout << *ret.back() << endl; //Outputs: "s"
    return ret;
}

По сути, я хочу иметь его, чтобы я мог объявить объект в теле функции, добавить его в вектор и иметь возможность снова изменить объектпозже в функции (в любое время в будущем) и смогу увидеть эти изменения везде, где у меня есть этот вектор. Это может быть легко сделано в Java, но у меня возникают проблемы с этим в C ++.

Ответы [ 4 ]

2 голосов
/ 21 октября 2019

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

Если вы хотите, чтобы объект выжил за пределами области, в которой он был создан, вы должны создать объект сдинамическое время жизни с использованием (прямо или косвенно) ключевого слова new. Помните, однако, что в C ++ нет сборщика мусора, поэтому для каждого использования new вы должны delete созданный объект, когда вы закончите с ним. Лучший способ сделать это - использовать смарт-указатель в некоторой форме, например std::unique_ptr или std::shared_ptr (который зависит от вашей конкретной ситуации):

std::vector<std::unique_ptr<std::string>> test() {
    std::vector<std::unique_ptr<std::string>> ret;
    std::unique_ptr<std::string> str = std::make_unique<std::string>("t");
    ret.push_back(std::move(str));
    //...
    return ret;
}

(std::make_unique использует new для создания нового объекта и возвращает std::unique_ptr к нему)


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

std::vector<std::string> test() {
    std::vector<std::string> ret;
    ret.push_back("t");
    //...
    return ret;
}
2 голосов
/ 21 октября 2019

Прекратите использовать указатели. Они имеют свое место в C ++, но не в коде, который вы опубликовали.

Конкретная проблема заключается в следующем:

string str = "t";
ret.push_back(&str);

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

Измените vector<string*> ret; на vector<string> ret;. Храните объекты вместо указателей, семантика значений легче рассуждать. Контейнеры и строки стандартной библиотеки предназначены для правильных действий и упрощения всего этого.

0 голосов
/ 21 октября 2019

Вы хотите изменить это:

string str = "t";
ret.push_back(&str);

На это:

string* str = new string("t");
ret.push_back(str);

Проблема в том, что в вашем исходном примере ваша строка уничтожается при выходе из test(), что означаетчто его адрес памяти теперь ни на что не указывает. Чтобы избежать этого, вы хотите выделить str в куче, используя указатель, чтобы память не очищалась после выхода из test().

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

for (string* i : ret) {
    delete i;
}
0 голосов
/ 21 октября 2019

Вы отбрасываете адрес локальной переменной. Когда переменная выходит из области видимости, этот адрес памяти освобождается.

Вместо этого вы можете использовать unique_ptr или shared_ptr, что-то вроде этого:

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

// #include "test.hpp"

using namespace std;
vector<std::shared_ptr<string>> test();

int main() {
    vector<std::shared_ptr<string>> ret = test();
    cout << ret.back() << endl; //Outputs: Memory of String str
    cout << *(ret.back()) << endl; //Outputs: "t"
}

vector<std::shared_ptr<string>> test() {
    vector<std::shared_ptr<string>> ret;
    const auto str = std::make_shared<string>("t");
    ret.push_back(str);
    cout << ret.back() << endl; //Outputs: Memory of String str
    cout << *(ret.back()) << endl; //Outputs: "t"
    return ret;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...