Почему в С++ возврат указателя частной переменной разных объектов приводит к ошибке сегментации?

#include <iostream>

class C
{
    private:
        int *o;
    public:
        C(int &i) { *o = i;}
        int* get_val() {return o;}
};

int main()
{
    int t = 9;
    C c(t);
    int* p = c.get_val();
    std::cout<<*p<<std::endl;
    int* h = c.get_val();           //seg fault
    std::cout<<*h<<std::endl;

    int f = 25;
    C g(f);
    int* q = g.get_val();           //seg fault
    std::cout<<*q<<std::endl;        

    return 0;
} 

В классе C есть два объекта: 'c' и 'g'. Возврат указателя частной переменной работает нормально в первый раз, но при повторном вызове это приводит к ошибке seg. Почему это так?

Итак, я закомментировал второй вызов и попытался создать новый объект, а вызванный попытался вернуть указатель частной переменной. Несмотря на то, что 'g' является другим объектом класса C, его возврат приводит к ошибке сегментации. Почему это так?


person Harikrishnan    schedule 20.11.2016    source источник
comment
C(int &i) { *o = i;} Это демонстрирует неопределенное поведение путем разыменования неинициализированного указателя. Возможно, вы имели в виду o = &i;. Демо   -  person Igor Tandetnik    schedule 20.11.2016


Ответы (3)


Конструктор C::C(int) не инициализирует переменную-член o. Он пытается писать через указатель o через *o=i, но поскольку o не инициализирован, результаты непредсказуемы.

person Waxrat    schedule 20.11.2016

Вы вообще не инициализируете C::o. Проблема не в том, что вы возвращаете закрытый указатель; это то, что вы назначаете память, которую вы не выделили.

Вот вывод gdb с точкой останова в строке 8 (конструктор C):

Breakpoint 1 at 0x400960: file tmp.cc, line 8.

Breakpoint 1, C::C (this=0x7fffffffdd00, i=@0x7fffffffdd08: 9) at tmp.cc:8
8         C(int &i) { *o = i;}
$1 = (int *) 0x7fffffffddf0
9
9

Breakpoint 1, C::C (this=0x7fffffffdce0, i=@0x7fffffffdcec: 25) at tmp.cc:8
8         C(int &i) { *o = i;}
$2 = (int *) 0x0

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400969 in C::C (this=0x7fffffffdce0, i=@0x7fffffffdcec: 25) at tmp.cc:8
8         C(int &i) { *o = i;}

На моей машине первый вызов прошел успешно, но второй вызов вызывает segfault, потому что g.o равен 0x0.

Вы должны инициализировать C::o перед назначением *o, например.

C(int &i) : o(new int) { *o = i;}
person Andrew    schedule 20.11.2016

In

C(int &i) { *o = i;}

Вы еще не выделили место для своего указателя перед выделением. Это должно было быть:

C(int i):o(new int){o=i;}

Но выделение памяти внутри функций класса требует систематического применения к ним delete/delete[]. Ну, это для предотвращения утечки памяти. Короче нужно:

C::~C(){
  delete o; // Freeing the memory associated with each object
}

Кроме того, я не могу придумать вариант использования для передачи значения по ссылке в вашей реализации. Поэтому я изменил C(int &i) на C(int i).

person sjsam    schedule 20.11.2016