pure virtual method called. abort...
От: varnie  
Дата: 21.06.08 03:44
Оценка:
здравствуйте.
натолкнулся на сабж, и не знаю куда смотреть. гугль не помог.
собственно говоря, проблема стала проявляться после того как я заменил:
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 оперирует еще неск. сущностями...
надеюсь, что укажете, куда в первую очередь смотреть. спасибо.
"Я женился на первой же женщине, которая обратилась ко мне по мейлу." © Л. Торвальдс
Re: pure virtual method called. abort...
От: Сергей Мухин Россия  
Дата: 21.06.08 05:21
Оценка: +3
Здравствуйте, varnie, Вы писали:


V>
V>  Result &Foo::process(){
V>      Result r;
V>      //...
V>      Result &rRef = r;
V>      return rRef;
V>  }
V>



returning address of local variable or temporary
---
С уважением,
Сергей Мухин
Re[2]: pure virtual method called. abort...
От: Аноним  
Дата: 21.06.08 05:38
Оценка:
Здравствуйте, Сергей Мухин.
я на это изначально обратил внимание, но меня сбил с пути следующий пример, найденный в одном из туторов в инете:
#include <iostream>
using namespace std;

double & GetWeeklyHours()
{
    double h = 46.50;
    double &hours = h;
    return hours;
}
//---------------------------------------------------------------------------
int main()
{
    double hours = GetWeeklyHours();

    cout << "Weekly Hours: " << hours << endl;

    return 0;
}

мне неясно, почему он корректен, а мой код в моем первом сообщении нет. на этих экспериментах я хочу просто понять, как таки правильно возвращать объект из ф-ции по ссылке. если мой пример в первом сообщении багавый, то как сделать правильно? допустим, я принципиально хочу возвращать результат ф-ции по ссылке. С++ это позволяет или нет?
спасибо за пояснение.
Re[3]: pure virtual method called. abort...
От: varnie  
Дата: 21.06.08 05:44
Оценка:
также сбило с толку, что g++ с флагом -Wall на меня не руганулса.
"Я женился на первой же женщине, которая обратилась ко мне по мейлу." © Л. Торвальдс
Re[3]: pure virtual method called. abort...
От: VoidEx  
Дата: 21.06.08 06:54
Оценка:
Здравствуйте, Аноним, Вы писали:

А>
А>double & GetWeeklyHours()
А>{
А>    static double h = 46.50;
А>    double &hours = h;
А>    return hours;
А>}
А>}


Может, там было так?
Re[4]: pure virtual method called. abort...
От: Сергей Мухин Россия  
Дата: 21.06.08 06:59
Оценка: -1
Здравствуйте, VoidEx, Вы писали:

VE>Здравствуйте, Аноним, Вы писали:


А>>
А>>double & GetWeeklyHours()
А>>{
А>>    static double h = 46.50;
А>>    double &hours = h;
А>>    return hours;
А>>}
А>>}


VE>Может, там было так?


За использование статических переменых внутри ф-ии без надобности — растрел!
---
С уважением,
Сергей Мухин
Re[5]: pure virtual method called. abort...
От: VoidEx  
Дата: 21.06.08 07:01
Оценка: 1 (1) +1
Здравствуйте, Сергей Мухин, Вы писали:

СМ>За использование статических переменых внутри ф-ии без надобности — растрел!


А за невникание в смысл вопроса что?
Re[3]: pure virtual method called. abort...
От: Сергей Мухин Россия  
Дата: 21.06.08 07:03
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Сергей Мухин.

А>я на это изначально обратил внимание, но меня сбил с пути следующий пример, найденный в одном из туторов в инете:

Учиться надо по книгам. Мало ли что в инете пишут!

А>мне неясно, почему он корректен, а мой код в моем первом сообщении нет. на этих экспериментах я хочу просто понять, как таки правильно возвращать объект из ф-ции по ссылке. если мой пример в первом сообщении багавый, то как сделать правильно?

A> допустим, я принципиально хочу возвращать результат ф-ции по ссылке. С++ это позволяет или нет?

Да позволяет.


А>спасибо за пояснение.
---
С уважением,
Сергей Мухин
Re[3]: pure virtual method called. abort...
От: rg45 СССР  
Дата: 21.06.08 07:19
Оценка: +2
Здравствуйте, <Аноним>, Вы писали:

А>
А>#include <iostream>
А>using namespace std;

А>double & GetWeeklyHours()
А>{
А>    double h = 46.50;
А>    double &hours = h;
А>    return hours;
А>}
А>}

А>мне неясно, почему он корректен, а мой код в моем первом сообщении нет. на этих экспериментах я хочу просто понять, как таки правильно возвращать объект из ф-ции по ссылке. если мой пример в первом сообщении багавый, то как сделать правильно? допустим, я принципиально хочу возвращать результат ф-ции по ссылке. С++ это позволяет или нет?

Конечно же, возвращать результат по ссылке можно, но при этом объект, на который мы ссылаемся должен продолжать существовать после выхода из функции. Таким объектом может быть либо глобальный объект, либо объект, располагающийся в динамической памяти, либо временный объект, созданный вызывающей функцией. Приведенный пример некорректен потому, что после выхода из функции 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>>
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: pure virtual method called. abort...
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 21.06.08 19:55
Оценка: -1 :)
Здравствуйте, Аноним, Вы писали:

А>мне неясно, почему он корректен, а мой код в моем первом сообщении нет. на этих экспериментах я хочу просто понять, как таки правильно возвращать объект из ф-ции по ссылке. если мой пример в первом сообщении багавый, то как сделать правильно? допустим, я принципиально хочу возвращать результат ф-ции по ссылке. С++ это позволяет или нет?

А>спасибо за пояснение.

Код из этого примера может сработать, хотя и не обязан, поскольку в стеке остаётся значение h.

Например, таким может быть состояние стека перед возвратом из GetWeeklyHours (адреса примерные, совпадения условные):

0x00: [hours@main]
0x08: [stack frame]
0x0C: [h@GetWeeklyHours] <- double-значение
0x14: [hours@GetWeeklyHours] <- ссылка на h@GetWeeklyHours


Если компилятор не решит чем-нибудь заглушить стек GetWeeklyHours после возврата, то возвращённая ссылка будет ссылаться на вполне корректное значение 46.50 по адресу 0x0C. Однако, оно с вероятностью близкой к 100% будет разрушено следующим вызовом какой-нибудь другой функции (да того же stream::operator << () ), которая в это место стека напихает своих локальных переменных.

Но если очень быстро подсуетиться и запихнуть это значение в какую-то переменную, не модифицировав при этом стек, то возможно, что чуть-чуть вырастет производительность. (Но я тебе этого не говорил!!!)

Но по-любому это UB, категорически неправильно и достойно всяческого порицания. Кстати, вот тут обсуждение примера с GetWeeklyHours.

А в исходном постинге у тебя вообще возвращается ссылка на разрушенный объект, т.е. у которого вызваны все деструкторы. Потому и PVC.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[4]: pure virtual method called. abort...
От: varnie  
Дата: 22.06.08 15:06
Оценка:
всем спасибо за толковые разъяснения. а то я уж думал у меня что-то с недопониманием, ибо я не мог таки понять, почему пример с сайта _якобы_ валиден. сейчас все встало на свои места, и мои предположения о его некорректности подтвердились.
"Я женился на первой же женщине, которая обратилась ко мне по мейлу." © Л. Торвальдс
Re[3]: pure virtual method called. abort...
От: Кодт Россия  
Дата: 24.06.08 12:35
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>я на это изначально обратил внимание, но меня сбил с пути следующий пример, найденный в одном из туторов в инете:


Тутор был криворукий, потому что.

А>#include <iostream>
А>using namespace std;

А>double & GetWeeklyHours()
А>{
А>    double h = 46.50;
А>    double &hours = h;
А>    return hours;
А>}
А>}
А>

А>мне неясно, почему он корректен, а мой код в моем первом сообщении нет.

Он тоже некорректен, но из-за некоторых особенностей x86 и косяков компилятора может оказаться работоспособным.
Дело в том, что литералы вещественных чисел, подобно литералам строк, хранятся в статическом хранилище — в секции констант.
Компилятор мог "срезать угол" и взять ссылку не на локальную переменную h, а на литерал.
Правда, здесь ещё и константность нарушается... поэтому, если там действительно неконстантная ссылка — то это баг компилятора и предпосылка к UB.

А> на этих экспериментах я хочу просто понять, как таки правильно возвращать объект из ф-ции по ссылке. если мой пример в первом сообщении багавый, то как сделать правильно? допустим, я принципиально хочу возвращать результат ф-ции по ссылке. С++ это позволяет или нет?


А каков смысл возвращения по ссылке? Чего ты хочешь добиться?

1) абстрагирование интерфейса от реализации
// .h
Interface foo();
// .cpp
Interface foo() { return Implementation(); }

2) полиморфизм
Interface foo()
{
    if(...) return One();
    if(...) return Two();
    .....
}

3) экономия на копировании (если не доверяешь оптимизациям RVO/NRVO, или если они заведомо не срабатывают)
void foo(Implementation& retval)
{
    retval.assign(.....);
}


Во всех вышеупомянутых случаях помогают указатели — начиная с std::auto_ptr с его эстафетной семантикой владения.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re: pure virtual method called. abort...
От: _ALeRT_  
Дата: 24.06.08 12:43
Оценка:
Здравствуйте, varnie, Вы писали:

V>здравствуйте.

V>натолкнулся на сабж, и не знаю куда смотреть. гугль не помог.

Какое-то время назад была статья на тему.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.