- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
//Сом ненужный щит
#include <iostream>
using namespace std;
#include <string>
#include <iostream>
struct Tracer {
Tracer(void)
:m_name("(none)")
{
std::cout << "[" << m_name << "] " << __PRETTY_FUNCTION__ << std::endl;
}
Tracer(const std::string & name)
:m_name(name)
{
std::cout << "[" << m_name << "] " << __PRETTY_FUNCTION__ << std::endl;
}
Tracer(const Tracer & other)
:m_name(other.m_name)
{
std::cout << "[" << m_name << "] " << __PRETTY_FUNCTION__ << std::endl;
}
Tracer(const Tracer && other)
:m_name(other.m_name)
{
std::cout << "[" << m_name << "] " << __PRETTY_FUNCTION__ << std::endl;
}
Tracer & operator=(const Tracer & other) {
m_name = other.m_name;
std::cout << "[" << m_name << "] " << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
Tracer & operator=(const Tracer && other) {
m_name = other.m_name;
std::cout << "[" << m_name << "] " << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
~Tracer() {
std::cout << "[" << m_name << "] " << __PRETTY_FUNCTION__ << std::endl;
m_name="You looser!";
}
std::string m_name;
};
//Тот щит, ради чего всё затевалось
template<class T> const T& Min(const T &x, const T &y) { return (x.m_name < y.m_name) ? x : y; }
int main() {
const Tracer& mr = Min(Tracer("a"), Tracer("b"));
cout<<"Some work with mr: "<<mr.m_name<<endl;
return 0;
}
LispGovno 04.02.2014 21:33 # +2
http://ideone.com/4J873s
bormand 04.02.2014 22:41 # 0
А ошибка, имхо, именно в сохранении ссылки на временный объект (один из трейсеров) в строке 53... Интересно, почему в этом коде временный объект умирает после вывода, а не до?
bormand 04.02.2014 22:49 # 0
LispGovno 04.02.2014 23:15 # +2
Избавится от const Tracer& не всегда возможно. Может быть важно для оптимизации. Юзают в паттерне RAII типа scope_exit. Иногда ссылка нужна для полиморфизма. Иногда нужна для того чтобы не было копирования. Да просто ответственность по возвращаемым ссылкам нужно возлагать на писателя функций, чтобы не плодить правила (правило: не возвращай ссылки на временные объекты - лучше из этого правила просто убрать последние слова и переписать как не возвращай ссылки вообще). В конце концов когда в функции вдруг появятся редкие условия с временными объектами, то ты вдруг как оказалось нарушил и ещё одно правило с возвращаемыми ссылками. Я тоже вспомнил, что я лажал именно так же. Банально соптимизировал. А потом через полгода исправил ошибку добавив редко исполняемое условия с временным объектом. Сейчас я понял что тогда исправив ошибку - я добавил новую. И эта ошибка не исправлена до сих пор в коде где-то.
bormand 04.02.2014 23:25 # 0
А где можно об этом почитать?
Ну а про невозврат ссылок согласен. Правда иногда надо, например скобки у контейнеров.
LispGovno 04.02.2014 23:42 # +1
& - не продливает.
const & продливает на один уровень. Ну то есть если ты напишешь перекачивание ссылки: из const A & в const A &, а из неё в const A& или в const B&, то это фейл. В конце жизни второй ссылки все пойдет в помойку и в третей ссылке уже может оказаться говно. Хотя конечно не обязано и компиляторы в некоторых случаях по ошибке или по стандарту могут сохранять жизнь и поэтому код может показывать неплохие жизненные показатели от компилятора к компилятору или от ключей компиляции к ключам компиляции.
Также ссылка до конца выражения доживет, например выражение:
f(m(), g(c, t(), d),m()); функция или конструктор g второй параметр принимает по константной ссылке, то до конца вызова g t() будет жить. После начала кода вызова f - t() уже если я правильно помню помрет. То есть сформированный во время вызова g временный объект (будь то объект типа g в случае конструктора или объект другого типа, если g функция) уже не будет иметь доступа к живому результату работы t(). Тот уже откинет копыта. Все что выше говорил - относится лишь к константным ссылкам. Не константные не продлевают, а это значит f(g()) - или UB или ошибка компиляции, если f принимает не константную ссылку. Вроде это любили превращать в UB без ошибки компиляции студии старые.
defecate-plusplus 05.02.2014 09:23 # +3
все заповеди там
[class.temporary]/5
LispGovno 04.02.2014 23:58 # +1
(std::initializer_list и конструкторам вызванным посредством {...} и агрегатным типам). Происходит ли при этом копирование объектов из {...}. Где они располагаются? В стеке? Как скоро умирают по отношению к ссылкам на них? Как это совместимо с alloca? Если кинет исключение 3тий объект в списке инициализации, то что произойдет? Все отматается? В обратном порядке?
guest 07.02.2014 12:16 # 0
bormand 07.02.2014 12:41 # 0
LispGovno 08.02.2014 23:41 # 0
bormand 04.02.2014 23:27 # 0
А что за паттерн? С ведрофона гуглить лениво.
LispGovno 04.02.2014 23:50 # 0
bormand 04.02.2014 23:53 # 0
LispGovno 08.02.2014 23:40 # 0
bormand 09.02.2014 07:41 # 0
LispGovno 09.02.2014 10:12 # 0
bormand 09.02.2014 11:11 # 0
bormand 09.02.2014 11:21 # 0
Потому что функция возвращает ссылку ;) По-моему этого факта достаточно, чтобы, по крайней мере, внимательно относиться к такой функции.
bormand 09.02.2014 11:25 # 0
LispGovno 09.02.2014 11:25 # +1
guest 04.02.2014 23:10 # −5
Dummy00001 05.02.2014 00:01 # 0
(протестил на 4.8.2 - с -Wall -Wextra нет ворнинга.)
как по мне: вот к чему приводит злоупотребление reference'ами. ;-)
PS ща пофикшу. заменяешь вот это:
template<class T> const T& Min(const T &x, const T &y) { return (x.m_name < y.m_name) ? x : y; }
на вот это:
#define Min( x, y ) ( (x).m_name < (y).m_name ? x : y )
и, о чудо, оно работает!
PPS я в таких случаях еще вывод (void *)this добавляю что бы видно было как именно объекты глючат.
bormand 05.02.2014 00:04 # +1
Dummy00001 05.02.2014 00:09 # 0
тестил, создает еще одну инстанцию объекта автоматом. и печатает корректно "а".
Bart 05.02.2014 00:23 # +1
WGH 05.02.2014 01:27 # +3
Я правильно понял?
LispGovno 05.02.2014 06:10 # +2
guest 18.04.2014 20:23 # 0