Недавно я столкнулся с проблемой, экспериментируя со связанными списками. Когда я использую функцию для связывания нового узла, который имеет строку в своем поле данных, он не работает. Под этим я подразумеваю, что когда функция (linkin(), см. Ниже) возвращается, строка (которая была локальной для функции) уничтожается, и поэтому поле строки кажется неинициализированным.
Однако, когда я делаю эту ту же операцию с int, похоже, все работает нормально. Код, который я использовал, ниже (его версия int, но сделайте val вместо строки int, чтобы увидеть другую версию). Может ли кто-нибудь объяснить мне, что происходит?
Благодарю!
struct testlist {
int val;
testlist *next;
};
void linkin ( testlist *a );
int main() {
testlist test;
linkin(&test);
cout << test.next->val <<endl;
}
void linkin ( testlist *a )
{
testlist b;
b.val=1;
a->next = &b;
cout << a->next->val <<endl;
}
testlist b;
a->next = &b;
a->next
указывает на локальный временный объект, который будет уничтожен сразу после возврата из функции. Он вызывает неопределенное поведение после разыменования его из функции.
Это неопределенное поведение, иногда это работает, иногда нет.
Также в C++ есть связанный список: std::list
. С другой стороны, вы можете использовать интеллектуальные указатели, такие как std::unique_ptr
вместо std::unique_ptr
указателей. Я написал смарт-указатель, основанный на вашем контейнере:
struct List
{
int val;
unique_ptr<List> next;
};
void linkin (List &a)
{
unique_ptr<List> b(new List);
b->val = 1;
a.next = move(b); // After move you can't use b anymore
cout << a.next->val << endl;
}
int main()
{
List test;
linkin(test);
cout << test.next->val <<endl;
}
Сразу, в linkin()
я могу видеть, что вы храните указатель в на объект, который собирается выходить за рамки - то есть: быть уничтожены. a
Есть причины, по которым это может показаться работающим с int, но не сложным типом, как std :: string. Несмотря на внешность, это сломанный код - попробуйте переписать linkin()
:
void linkin ( testlist& a )
{
testlist* b = new testlist;
b->val=1;
a->next = b;
cout << a->next->val <<endl;
}
new
без умного указателя - действительно хороший совет!