- 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;
}
                                 
        
http://ideone.com/4J873s
А ошибка, имхо, именно в сохранении ссылки на временный объект (один из трейсеров) в строке 53...Интересно, почему в этом коде временный объект умирает после вывода, а не до?
Избавится от const Tracer& не всегда возможно. Может быть важно для оптимизации. Юзают в паттерне RAII типа scope_exit. Иногда ссылка нужна для полиморфизма. Иногда нужна для того чтобы не было копирования. Да просто ответственность по возвращаемым ссылкам нужно возлагать на писателя функций, чтобы не плодить правила (правило: не возвращай ссылки на временные объекты - лучше из этого правила просто убрать последние слова и переписать как не возвращай ссылки вообще). В конце концов когда в функции вдруг появятся редкие условия с временными объектами, то ты вдруг как оказалось нарушил и ещё одно правило с возвращаемыми ссылками. Я тоже вспомнил, что я лажал именно так же. Банально соптимизировал. А потом через полгода исправил ошибку добавив редко исполняемое условия с временным объектом. Сейчас я понял что тогда исправив ошибку - я добавил новую. И эта ошибка не исправлена до сих пор в коде где-то.
А где можно об этом почитать?
Ну а про невозврат ссылок согласен. Правда иногда надо, например скобки у контейнеров.
& - не продливает.
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 без ошибки компиляции студии старые.
все заповеди там
[class.temporary]/5
(std::initializer_list и конструкторам вызванным посредством {...} и агрегатным типам). Происходит ли при этом копирование объектов из {...}. Где они располагаются? В стеке? Как скоро умирают по отношению к ссылкам на них? Как это совместимо с alloca? Если кинет исключение 3тий объект в списке инициализации, то что произойдет? Все отматается? В обратном порядке?
А что за паттерн? С ведрофона гуглить лениво.
Потому что функция возвращает ссылку ;) По-моему этого факта достаточно, чтобы, по крайней мере, внимательно относиться к такой функции.
(протестил на 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 добавляю что бы видно было как именно объекты глючат.
тестил, создает еще одну инстанцию объекта автоматом. и печатает корректно "а".
Я правильно понял?