здравствуйте.
натолкнулся на сабж, и не знаю куда смотреть. гугль не помог.
собственно говоря, проблема стала проявляться после того как я заменил:
class Foo{
public:
//...
Result process(){
Result r;
//...return r;
};
};
на возвращение по ссылке:
Result &Foo::process(){
Result r;
//...
Result &rRef = r;
return rRef;
}
все это дело вызывается сл. образом:
Result res = foo.process();
Bar bar(res);
bar.run();
сабж вылетает где-то в недрах Bar::run(), в одном из вызываемых им методов Bar.
workaround более кратко не получится привести, т.к. класс Fred оперирует еще неск. сущностями...
надеюсь, что укажете, куда в первую очередь смотреть. спасибо.
мне неясно, почему он корректен, а мой код в моем первом сообщении нет. на этих экспериментах я хочу просто понять, как таки правильно возвращать объект из ф-ции по ссылке. если мой пример в первом сообщении багавый, то как сделать правильно? допустим, я принципиально хочу возвращать результат ф-ции по ссылке. С++ это позволяет или нет?
спасибо за пояснение.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Сергей Мухин. А>я на это изначально обратил внимание, но меня сбил с пути следующий пример, найденный в одном из туторов в инете:
Учиться надо по книгам. Мало ли что в инете пишут!
А>мне неясно, почему он корректен, а мой код в моем первом сообщении нет. на этих экспериментах я хочу просто понять, как таки правильно возвращать объект из ф-ции по ссылке. если мой пример в первом сообщении багавый, то как сделать правильно? A> допустим, я принципиально хочу возвращать результат ф-ции по ссылке. С++ это позволяет или нет?
А>мне неясно, почему он корректен, а мой код в моем первом сообщении нет. на этих экспериментах я хочу просто понять, как таки правильно возвращать объект из ф-ции по ссылке. если мой пример в первом сообщении багавый, то как сделать правильно? допустим, я принципиально хочу возвращать результат ф-ции по ссылке. С++ это позволяет или нет?
Конечно же, возвращать результат по ссылке можно, но при этом объект, на который мы ссылаемся должен продолжать существовать после выхода из функции. Таким объектом может быть либо глобальный объект, либо объект, располагающийся в динамической памяти, либо временный объект, созданный вызывающей функцией. Приведенный пример некорректен потому, что после выхода из функции GetWeeklyHours, переменная (временный объект) h перестает существовать, а возвращенная ссылка невалидна, поскольку ссылается на стековый мусор. Обращение к объекту по такой ссылке приводит к неопределенному поведению (undefined behavior). Неопределенное поведение означает, что результат непредсказуем, яркий тому пример — "pure virtual called". Догадаться почему вылезла именно эта ошибка несложно, но это уже не так существенно.
Вот несколько примеров, когда возвращение результа по ссылке правомерно:
Возвращение ссылки на глобальную переменную:
int x = 123;
int& foo()
{
return x;
}
Возвращение ссылки на статическую переменную, определенную в теле вызываемой функции:
int& foo()
{
static int x = 123; //статическая переменнаяreturn x;
}
Возвращение ссылки на переменную, расположенную в динамической памяти:
int& foo()
{
int* p = new int(123);
register_to_be_deleted(p); //кто-то должен освобождать выделенную памятьreturn *p;
}
Возвращение ссылки на переменную, переданную в вызываемую функцию по ссылке или указателю
int& foo(int& x)
{
return x;
}
Возвращение ссылки на переменную-член класса
class A
{
public:
int& foo() { return x; }
private:
int x;
};
... << RSDN@Home 1.2.0 alpha rev. 787>>
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Аноним, Вы писали:
А>мне неясно, почему он корректен, а мой код в моем первом сообщении нет. на этих экспериментах я хочу просто понять, как таки правильно возвращать объект из ф-ции по ссылке. если мой пример в первом сообщении багавый, то как сделать правильно? допустим, я принципиально хочу возвращать результат ф-ции по ссылке. С++ это позволяет или нет? А>спасибо за пояснение.
Код из этого примера может сработать, хотя и не обязан, поскольку в стеке остаётся значение h.
Например, таким может быть состояние стека перед возвратом из GetWeeklyHours (адреса примерные, совпадения условные):
Если компилятор не решит чем-нибудь заглушить стек GetWeeklyHours после возврата, то возвращённая ссылка будет ссылаться на вполне корректное значение 46.50 по адресу 0x0C. Однако, оно с вероятностью близкой к 100% будет разрушено следующим вызовом какой-нибудь другой функции (да того же stream::operator << () ), которая в это место стека напихает своих локальных переменных.
Но если очень быстро подсуетиться и запихнуть это значение в какую-то переменную, не модифицировав при этом стек, то возможно, что чуть-чуть вырастет производительность. (Но я тебе этого не говорил!!!)
Но по-любому это UB, категорически неправильно и достойно всяческого порицания. Кстати, вот тут обсуждение примера с GetWeeklyHours.
А в исходном постинге у тебя вообще возвращается ссылка на разрушенный объект, т.е. у которого вызваны все деструкторы. Потому и PVC.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
всем спасибо за толковые разъяснения. а то я уж думал у меня что-то с недопониманием, ибо я не мог таки понять, почему пример с сайта _якобы_ валиден. сейчас все встало на свои места, и мои предположения о его некорректности подтвердились.
А>мне неясно, почему он корректен, а мой код в моем первом сообщении нет.
Он тоже некорректен, но из-за некоторых особенностей x86 и косяков компилятора может оказаться работоспособным.
Дело в том, что литералы вещественных чисел, подобно литералам строк, хранятся в статическом хранилище — в секции констант.
Компилятор мог "срезать угол" и взять ссылку не на локальную переменную h, а на литерал.
Правда, здесь ещё и константность нарушается... поэтому, если там действительно неконстантная ссылка — то это баг компилятора и предпосылка к UB.
А> на этих экспериментах я хочу просто понять, как таки правильно возвращать объект из ф-ции по ссылке. если мой пример в первом сообщении багавый, то как сделать правильно? допустим, я принципиально хочу возвращать результат ф-ции по ссылке. С++ это позволяет или нет?
А каков смысл возвращения по ссылке? Чего ты хочешь добиться?