Назначить временный указатель на структуру в качестве члена структуры - PullRequest
0 голосов
/ 01 апреля 2020

Допустим, у меня есть следующие структуры:

struct Foo
{
  int val;
};
struct Test
{
  Foo *bar;
};

, и я хотел создать Test структуру:

Test get_test()
{
  Test test;
  Foo foo;
  foo.val = 10;
  test.bar = &foo;

  cout << "INIT: " << test.bar->val << endl;

  return test;
}

int main()
{
    Test test = get_test();
    cout << "AFTER: " << test.bar->val << endl;
    return 0;
}

Вывод следующий:

INIT: 10
AFTER: 32723

Я пытался сделать это по-другому:

Test get_test()
{
  Test test;
  Foo *foo;
  foo->val = 10;
  test.bar = foo;

  cout << "INIT: " << test.bar->val << endl;

  return test;
}

Но это дало мне SIGSEGV (Address boundary error)

Из моего ограниченного понимания я считаю, что это потому, что в get_test() foo - временная переменная, поэтому ссылка ничего не значит. Как я могу сделать это правильно?

1 Ответ

1 голос
/ 01 апреля 2020

Вы на правильном пути. В вашем первом примере, когда get_test вернется, foo больше не будет существовать, и доступ к адресу, на котором он находился, является неопределенным поведением. То же самое происходит во второй попытке, но здесь проблема в самом get_test. Вы объявляете Foo* foo;, но никогда не назначаете его чему-либо, что означает, что переменная foo указывает на некоторый случайный адрес. Доступ к нему - неопределенное поведение. Попробуйте это как вашу get_test -функцию:

Test get_test()
{
  Test test;
  Foo *foo = new Foo();
  foo->val = 10;
  test.bar = foo;

  cout << "INIT: " << test.bar->val << endl;

  return test;
}

Здесь мы выделяем foo с new, так что она выделяется в куче и будет оставаться до тех пор, пока вы не вызовете delete для нее , Это означает, что вы должны убедиться, что delete это, как только вы закончите с этим, иначе у вас будет утечка памяти. В C ++ 14 вы также можете сделать это, используя std::unique_ptr:

struct Test
{
  std::unique_ptr<Foo> bar;
};
{
  Test test;
  std::unique_ptr<Foo> foo = std::make_unique<Foo>();
  foo->val = 10;
  test.bar = std::move(foo);

  cout << "INIT: " << test.bar->val << endl;

  return test;
}

std::unique_ptr позаботится об удалении foo, как только он выйдет из области видимости (когда test уничтожен), и вам не нужно беспокоиться об утечках памяти (но вы не можете скопировать std::unique_ptr, поэтому вам придется std::move его). std::unique_ptr доступно с c ++ 11, std::make_unique с c ++ 14. Вам также нужно будет #include <memory>, чтобы иметь возможность их использовать. Проверьте эту ссылку , чтобы узнать больше о разнице между кучей и стеком, и эту , чтобы узнать больше о std::unique_ptr и семантике перемещения.

...