2015-03-03 2 views
0

Не могли бы вы взглянуть на эти 2 примера и объяснить, почему первый результат печати дал мне неправильный номер?Передача C++ возвращала ссылку непосредственно на функцию

Первый пример (printRes передать х на указатель):

int& getInt(int x){ 
    x++; 
    cout << "int " << x << endl; 
    return x; 
} 

void printRes(int *x){ 
    cout << "res " << *x << endl; 
} 

int main() 
{ 
    int t = getInt(5); 
    printRes(&getInt(5)); // first attemp 
    printRes(&t); // second attemp 

    return 0; 
} 

Второй пример (printRes передать х посредством ссылки):

int& getInt(int x){ 
    x++; 
    cout << "int " << x << endl; 
    return x; 
} 

void printRes(int &x){ 
    cout << "res " << x << endl; 
} 

int main() 
{ 
    int t = getInt(5); 
    printRes(getInt(5)); // first attemp 
    printRes(t); // second attemp 

    return 0; 
} 

Результаты:

int 6 
int 6 
res 2686640 
res 6 

Когда я пройти «x» по значению работает нормально, но моя цель - получить что-то вроде этого:

  • функция GetInt создает объект, помещает его в вектор (так что я просто называю v.emplace_back()) и возвращает ссылку на данный момент добавлен объект (v.back())
  • значение, возвращенное GetInt передается printRes который заполняет объект со значениями из файла

Я не хочу создавать временные переменные, такие «т», но передать векторный элемент непосредственно к функции printRes, но в моем более расширенном случае у меня есть сбои в деструкторов (или иногда в некоторых случайных места).

+0

Вы можете [спросить у компилятора] (http://coliru.stacked-crooked.com/a/d20873013cc5dd8b): * предупреждение: ссылка на стек памяти, связанная с локальной переменной 'x', возвращена * – chris

+0

Спасибо, теперь я см. проблему. Интересно Visual не сообщает об этом waring. – Harry

+0

В предварительном просмотре VS2015 я получаю * предупреждение C4172: возвращающий адрес локальной переменной или временный: x *. Я не знаю о других версиях. – chris

ответ

0

Причина, по которой первый вызов printRes() дает неверный результат, состоит в том, что getInt() имеет серьезный недостаток.

Проблема заключается в том, что getInt() возвращает ссылку на локальную переменную, и это не выход на C++. В момент получения getInt() переменная x больше не существует, и любая ссылка на переменную становится недействительной. В результате указатель, который printRes() принимает в строке:

printRes(&getInt(5)); 

скорее всего указывает на ерунду. Тот же аргумент касается второго примера.

Причина, по которой второй вызов printRes() дает вам правильный результат - удача. Когда инвалид ссылка возвращаются в строке:

int t = getInt(5); 

переменная т инициализируется со значением х, а потому, что это происходит сразу после GetInt() возвращает память, где хранятся й еще не была перезаписана ,

В любом случае возвращение ссылки - это то, о чем вы должны быть осторожны. Выезд Is the practice of returning a C++ reference variable, evil?

Одним из способов сделать то, что вы хотите, является определение вектора v, который не является локальным в getInt() (поэтому он может существовать вне сферы действия функции) и вместо этого возвращать итератор. Как это:

#include <iostream> 
#include <vector> 

using namespace std; 

vector<int> v; 

vector<int>::iterator getInt(int x){ 
    x++; 
    cout << "int " << x << endl; 
    v.emplace_back(x); 
    return --v.end(); // end() points to after last element. 
         // Decrement to get the last element 
} 

void printRes(vector<int>::iterator i){ 
    cout << "res " << *i << endl; 
    *i = 99; //set the element to a new value if you want 
} 

int main() 
{ 
    printRes(getInt(5)); 

    return 0; 
} 

Пожалуйста, обратите внимание, что итератор вернулся из GetInt() получает признан недействительным, когда v.emplace_back) (или аналогичные функции) используется (, так что вы не должны хранить его слишком долго. Однако, используя это немедленно, как здесь, прекрасно.

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