Возврат ссылки на элемент контейнера члена класса

Foo ведет себя как круговой итератор. Несмотря на то, что я нервничаю по этому поводу, приведенный ниже код компилируется нормально, но создает ошибку во время выполнения. Я получаю сообщение об ошибке, даже если удаляю константы из get_current(). Конечно, я могу вернуть указатель, и он будет работать; однако получу ли я лучшую безопасность, возвращая ссылку?

#include <iostream>
#include <array>
#include <memory>

class Foo
{
public:
  Foo();
  void next();
  const int& get_current() const;
private:
  std::array<std::unique_ptr<int>, 3> arr_;
  unsigned i_;
};

Foo::Foo() : i_(0)
{
  arr_[0] = std::unique_ptr<int>(new int(5));
  arr_[1] = std::unique_ptr<int>(new int(6));
  arr_[2] = std::unique_ptr<int>(new int(7));
}

void Foo::next()
{
  ++i_;
  i_ %= 3;
}

const int& Foo::get_current() const 
{
  return *arr_[i_];
}

int main()
{
  Foo foo;
  int* p;

  *p = foo.get_current();
  //do something with p
  std::cout << *p << std::endl;

  foo.next();
  *p = foo.get_current();
  //do something with p
  std::cout << *p << std::endl;

  return 0;
}

3 ответа

Решение
int* p;

Это неинициализированный указатель, не указывающий ни на что. Разыменование дает неопределенное поведение.

*p = foo.get_current();

Это разыменовывает неверный указатель. Boom!

Возможно, вы хотите, чтобы он указывал на элемент массива

p = &foo.get_current();

или, возможно, вы хотите копию элемента массива

int n;
n = foo.get_current();

foo.get_current(); вполне может быть возвращение const ссылка, но после этого вы пытаетесь получить значение копии этого при назначении *p,

Назначение *p это то, что вызывает у вас проблемы, как p неинициализирован. Это неопределенное поведение, которое в вашем случае проявляется как ошибка времени выполнения.

Вы можете использовать код как const int& p = foo.get_current(); но имейте в виду, что ссылку можно связать только один раз, поэтому вам нужно быть осторожным с областью видимости.

Или вы можете использовать std::shared_ptr<int> и сделать это тип возврата get_current()и полностью лишить ваш код голых указателей.

*p = ... Вы разыменование int* P без надлежащей инициализации.

Измените свой код в главном на

 int p; // Remove *

 p = foo.get_current();
 //do something with p
 std::cout << p << std::endl;

или если вы действительно хотели использовать указатель

 const int* p;

 p = &foo.get_current();
  // ^ Take the address
Другие вопросы по тегам