2013-11-02 4 views
1

Можете ли вы рассказать мне, почему вывод этого ссылочного члена класса отличается от разных компиляторов?
Инициализация списка членов класса

class B 
    { 
    int& aRef; 
    public: 
    B(int c):aRef(c){} 

    void Print() 
    { 
     cout<<aRef<<endl; 
    } 
    }; 

    void f(int s) 
    { 
    int& lcRef=s; 
    cout<<lcRef<<endl; 
    } 

int main() 
{ 
    int x=100; 
    B s(x); 
    s.Print(); //ms c++ output : 3323244, gcc output :100 
    f(x); //ms c++ output : 100, gcc output:100 
    return 0; 
} 


И второй параметр вопрос функции f(int s) ведет себя такую ​​же логику, что застройщик в инициализации класса Б?

+2

Вы сохраняете ссылку на временный (на 'Int c'parameter в' b' конструктора). Как только конструктор будет завершен, он больше не находится в области видимости, будет уничтожен, и тогда у вас будет свисающая ссылка. Доступ к нему после этого - ** неопределенное поведение **. – WhozCraig

ответ

5
B(int c):aRef(c){} 

Это связывает ссылку на аргумент конструктора c. Поскольку он передается по значению, он разрушается, когда конструктор возвращается, оставляя ссылку на свидание. Доступ к нему после возврата конструктора дает неопределенное поведение; в этом случае он пытается получить доступ к единице освобожденной памяти стека, которая может или не может быть еще доступна, и может или не может содержать старое значение.

Вы хотите передать по ссылке, чтобы привязать к переменному вызывающему абоненту:

B(int& c) : aRef(c) {} 
+0

gotcha, поэтому, если изменить тип возврата f() на int & и просто вернуть lcRef без использования cout, это будет неопределенное поведение, такое же, как и для конструктора? –

+0

woow awsome теперь я могу понять, почему прохождение по ссылке существует? проклятый язык программирования .. спасибо –

+0

@DonCarleone: Да, возврат ссылки на локальную переменную также даст неопределенное поведение, если кто-либо использует ссылку. Компиляторы обычно предупреждают об этих проблемах, если вы включаете предупреждения. –

4

f функции правильно и работает, как ожидалось, но здесь:

B(int c):aRef(c){} 

Вы в основном присваивание int& aRef адреса для локального автоматического выделенного переменных (c). Теперь ссылки более безопасны, чем указатели, но назначение автоматической выделенной переменной, выходящей за рамки, является одним из немногих случаев, которые делают их недействительными.

Тот факт, что вывод правилен в GCC, не подразумевает ничего, поскольку эта переменная недействительна больше, чем конструктор.

+0

+1. Нельзя даже сказать с точностью, что результат «правильный» на GCC, поскольку сам термин требует окончательного вывода, условие, совершенно отсутствующее по самой природе неопределенного (иначе говоря, никакого определения) поведения. – WhozCraig

2

Разница в том, что в пределахf, вы принимаете ссылку на параметр. Этот параметр сохраняется, когда вы печатаете контент по ссылке. Для конструктора B вы находитесь , сохраняя ссылку, и когда конструктор заканчивается, объект, на который ссылается, выходит из области видимости, поэтому ссылка становится оборванной ссылкой, и использование ее становится недействительным. Выход из GCC - это просто совпадение, но оно не гарантируется.

Смежные вопросы