LINUX.ORG.RU

[c++] так все-таки баг языка или компилятора? (у кого есть icc, посмотрите)

 


0

0

В случае op_x и op_y копилятор, ИМХО, позволяет создать неконстантную ссылку на временный объект, который затем деструктируется. В совершенно аналогичном им op_z компилятор это не позволяет.

Выхлоп показывает, что с4 и с5 — это ссылки на мертвые объекты (т.е. объекты, у которых отработал деструктор)

#include <iostream>
using namespace std;

class C
{
public:
  C(int i): i(i), s("live") { cout << "ctor: " << i << endl; }
  C operator+(const C& c)  { cout << "plus: " << i << "+" << c.i << endl; return C(i+c.i); }
  C& operator+(int ii) { cout << "op_x: " << i << "+" << ii << endl; i += ii; return *this; }
  C& op_y(int ii) { cout << "op_y: " << i << "+" << ii << endl; i += ii; return *this; }
  friend C& op_z(C& that, int ii) {
    cout << "op_z: " << that.i << "+" << ii << endl;
    that.i += ii;
    return that;
  }
  void info() const { cout << "info: " << i << " " << s << endl; }
  ~C() { s="dead"; cout << "dtor: " << i << endl; }
private:
  int i;
  const char* s;
};
int main()
{
  C c1(1);
  C c2(2);
  const C& c3 = (c1+c2);
  const C& c4 = (c1+c2)+1;
  const C& c5 = (c1+c2).op_y(2);
  c1.info();
  c2.info();
  c3.info();
  c4.info();
  c5.info();
#ifdef C6
  const C& c6 = c3+3;
  c6.info();
#endif
#ifdef C7
  const C& c7 = op_z(c1+c2, 4);
  c7.info();
#endif
  return 0;
}

$ g++ -DC6 -Wall b.cxx
b.cxx: In function ‘int main()’:
b.cxx:35: error: passing ‘const C’ as ‘this’ argument of ‘C& C::operator+(int)’ discards qualifiers
$ g++ -DC7 -Wall b.cxx
b.cxx: In function ‘int main()’:
b.cxx:39: error: invalid initialization of non-const reference of type ‘C&’ from a temporary of type ‘C’
b.cxx:11: error: in passing argument 1 of ‘C& op_z(C&, int)’
$ g++  -Wall b.cxx
$ ./a.out
ctor: 1
ctor: 2
plus: 1+2
ctor: 3
plus: 1+2
ctor: 3
op_x: 3+1
dtor: 4
plus: 1+2
ctor: 3
op_y: 3+2
dtor: 5
info: 1 live
info: 2 live
info: 3 live
info: 4 dead
info: 5 dead
dtor: 3
dtor: 2
dtor: 1
$

**/
★★★★★

Последнее исправление: www_linux_org_ru (всего исправлений: 2)
Ответ на: комментарий от anonymous

> Так и на С++ можно писать абсолютно непонятные программы. Иначе есть Java и т.п., её и придумали для избавления от сложных сторон С++.

Эти отмазки не прокатывают — вон в моем примере в случае оформления функции другом компилятор прекрасно ловит ошибку, а в случае оформления методом — не ловит и приводит к ссылке на мертвый объект.

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от www_linux_org_ru

Через каждое сообщение пишется, что C& operator+(double x) возвращает не объект, а ссылку и что временный объект будет поэтому уничтожен в конце выражения.

anonymous
()
Ответ на: комментарий от www_linux_org_ru

так и не прочитали дизайн и эволюцию ? :) инициализация константной ссылки работает особенно только при присвоении самого временного объекта. в определении оператора ошибок нет, в присвоении ссылке чего-угодно ошибок нет, а проводить анализ того, что вернула функция ссылку на временные объект и присвоился он ссылке - не просто и не всегда работает

gavv
()
Ответ на: комментарий от www_linux_org_ru

Огромный пример сводится к поиску перегрузки

class C
{
};
C glob;
C& g(C&, double) { return glob;}
C g(double, C&) {return C();}

int main()
{
	C c;
	C w = g(g(2.1, c), 3.1);
	return 0;
}
w.cpp: In function ‘int main()’:
w.cpp:11: error: no matching function for call to ‘g(C, double)’
w.cpp:5: note: candidates are: C& g(C&, double)
w.cpp:6: note:                 C g(double, C&)
w.cpp:11: warning: unused variable ‘w’
В данном случае неконстантная ссылка параметра C& g(C&, double) пытается инициализироваться временным объектом g(2.1, c). Надо исправить C& g(const C&, double) { return glob;}

anonymous
()
Ответ на: комментарий от www_linux_org_ru

>Эти отмазки не прокатывают — вон в моем примере в случае оформления функции другом компилятор прекрасно ловит ошибку, а в случае оформления методом — не ловит и приводит к ссылке на мертвый объект.

Нет ошибок в работе компилятора в обоих случаях. В случае оформления другом компилятор ловит ошибку про инициализацию неконстантной ссылки временным объектом. В случае оформления методом возвращается ссылка, а не объект. И временный объект удаляется в конце выражения.

anonymous
()
Ответ на: комментарий от anonymous

> Через каждое сообщение пишется, что C& operator+(double x) возвращает не объект, а ссылку и что временный объект будет поэтому уничтожен в конце выражения.

И ты думаешь я это не понял? Понял конечно.

И уже не раз писал, что такое поведение — это баг языка.

Последний раз напишу почему: т.к. это поведение нежелается программистом, ошибка ловится при френдовой форме оператора, но НЕ ловится при методовой форме оператора.

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от www_linux_org_ru

Всё дело в механизме передачи неявного параметра в метод: в operator op_z параметр that — явный и является неконстантной ссылкой; В случае же метода временный объект передаетсяс через указатель this.

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

op_x(&(c1+c2), 1)

Запиши свой op_z как operator op_z(C *, int)

anonymous
()
Ответ на: комментарий от www_linux_org_ru

>Последний раз напишу почему: т.к. это поведение нежелается программистом
Что значит не желается? Если я пишу одно, а желаю другое, то это баг языка? Вы возвращаете ссылку, а не объект, автоматический объект чисто физически не может жить после выхода из области видимости. Передача ссылки на объект это не ошибка. Вам уже объяснили, что компилятор пишет ошибку о другом.

Booster ★★
()
Ответ на: комментарий от anonymous

> В случае же метода временный объект передаетсяс через указатель this

this чисто по историческим причинам оказался указателем, на самом же деле он всегда не 0 и не может инкрементироваться — т.е. он на самом деле ссылка

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от www_linux_org_ru

Это уже бесполезно объяснять. Приравнять разные типы ошибок. Логическая ошибка программиста, не знающего работу со временными объектами, и ошибка в программе с попыткой инициализации неконстантной ссылки в параметре функции временным объектом. Начинает напоминать троллинг.

anonymous
()
Ответ на: комментарий от www_linux_org_ru

> в первом случае gcc не пропускает бажистый код (правда, выдавая невнятную причину, а истинная, вроде бы — нельзя инициализировать аргумент-неконстантную-ссылку временным объектом)

во втором случае ( -DINNOCENT_CHANGE ) делаем ну совершенно несущественное изменение — переделывает друга в метод, и вуаля — комплятор заткнулся, а в рантайме имеем ссылку на мертвый объект

Да, инетерсно. Никогда так сильно не заморачивался в стандарт цпп. Тут и неязыковых ошибок имхо хватает. Только замечу что местечковый msvc2010beta2 компилит оба варианта. Результат такойже.

yatagarasu
()
Ответ на: комментарий от anonymous

> Логическая ошибка программиста, не знающего работу со временными объектами, и ошибка в программе с попыткой инициализации неконстантной ссылки в параметре функции временным объектом. Начинает напоминать троллинг.

Все зависит от цели. Если цель — обучение программиста, то вывод «компилятор следует стандарту», а если цель — оценка языка, то вывод «язык как минимум непоследователен, а то и содержит баг».

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от anonymous

> Начинает напоминать троллинг.

Впрочем, ты меня еще можешь убедить в последовательности поведения языка, если объяснишь, отчего такая разница между френдом и методом (или убедишь, что this *по факту* указатель, а не ссылка).

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от www_linux_org_ru

Дык потому как: «3.1+c1» является rvalue(значение), а значение можно привести можно только к константной ссылке. Например 5 является значением, а не объектом. Компилятор тупо интерпретирует выражения и поступает сообразно их специфике.

Booster ★★
()
Ответ на: комментарий от www_linux_org_ru

Вообще-то можно сделать delete this; This, может быть и по историческим причинам, но указатель.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.