пятница, 2 марта 2012 г.

Любоыптное поведение константной ссылки в C++

Очень любопытно поведение константных ссылок в C++. Потому что константная ссылка - это не просто указатель. Если присвоить ей значение временного объекта, то он будет существовать столько же, сколько и константная ссылка. Это, как ни странно, записано в стандарте. О чем я прочитал в блоге алены-цпп. Но это еще не все:

class SomeClass {
public:
    SomeClass(const std::string & name)  
      : obj_name(name)  
    { 
       std::cout << "object \"" << obj_name.c_str() << "\" created" << std::endl; 
    }
    ~SomeClass()  
    { 
       std::cout << "object \"" << obj_name.c_str() << "\" destroyed" << std::endl;  
    }
private:
    std::string obj_name;
};
SomeClass get_some_class_heap() {
    return *(new SomeClass("HeapObjectFromFunc"));
}
SomeClass get_some_class_val() {
    return SomeClass("ValueObjFromFunc");
}
void test_const_ref_func() {     
    const SomeClass & value_obj_from_func_ref(get_some_class_val()); // 1    
    const SomeClass & heap_obj_from_func_ref(get_some_class_heap()); // 2    
    const SomeClass & heap_obj_ref(*(new SomeClass("HeapObj"))); // 3   
    // 
    std::cout << "end of const_ref_func()" << std::endl;
}
int main(int argc, char *argv[])
{  
 
    test_const_ref_func();
 
}

Получаем вот такой вот вывод:

object "HeapObjectFromFunc" created
object "ValueObjFromFunc" created
object "HeapObj" created
end of const_ref_func()
object "ValueObjFromFunc" destroyed
object "HeapObjectFromFunc" destroyed

 
Первый случай - все понятно: константная ссылка получает временный value-объект и "держит" его, не давая ему умереть, пока сама не выйдет за пределы области видимости функции test_const_ref_func().
Второй случай - то же самое, но возвращается ссылка не на value-объект, а на объект, созданный в куче. Казалось бы - вот они, умные указатели! Но... см.третий случай.
Третий случай - умный указатель получает ссылку на тут же динамически созданный объект. Разумеется, он не удаляет объект после того, как выходит за пределы видимости. Если бы было иначе - отладка программ на C++ была бы еще более непредсказуемой и сложной задачей, чем даже сейчас. И, кстати, поведение компилятора в этом плане во втором случае тоже вызывает много вопросов.
 
 

2 комментария:

  1. Во втором случае нет ничего странного.

    То, что у вас:
    SomeClass get_some_class_heap() - вызывает конструктор копирования, затем создает и возвращает временный объект. Константная ссылка в свою очередь "продляет" жизнь этого объекта до конца блока void test_const_ref_func().

    Должно быть:
    SomeClass& get_some_class_heap() - возвращет ссылку на heap-объект. Heap-объект не является временным объектом, константная ссылка никак не меняет время его жизни.

    Во втором случае у вас утечка памяти.

    ОтветитьУдалить
  2. Небольшое уточнение. В варианте приведенном мной SomeClass& get_some_class_heap() константная ссылка не влияет на время жизни объекта не только потому, что это heap-объект, но и потому, что инициализация происходит ссылкой, а не объектом.

    ОтветитьУдалить