Pull to refresh

Comments 12

Вы не совсем правы. Компилятор не удаляет просто так конструкторы копирования, а может удалить только пару констуктор копирования-деструктор. Так что, если ваши конструктор копирования и деструктор не имеют побочных эффектов (а с чего бы им?), а деструктор просто «отменяет» действие конструктора копирования то ничего страшного и достойного громкой статьи с подзаголовком «Страшная правда» тут нет.
По идее, retain/release пара должна обладать именно такой семантикой, и на первый взгляд непонятно, как у вас получилось сделать иначе.
Да, вы совершенно правы. Я провёл дополнительные тесты — статья требует серьёзных уточнений… Постараюсь внести правки как можно скорее.

По поводу уточнённой проблемы задавал ещё вопрос на stack overflow. Там люди дали достаточно хороший ответ.
А почему у вас ожидаемый результат
Default
Const Copy
Call 1
Destroy

? Два раза Destroy же должен случиться, 1 раз для временного объекта после Const Copy, и уничтожить тот, который первым написал Default, а второй раз в конце. Вот этот второй деструктор и схлопнулся с копирующим конструктором. В таких дебажных строках очень полезно печатать значение this.

Кстати, в gcc есть ещё похожая оптимизация, связанная с возвращаемым из функции значением.
Кстати, в gcc есть ещё похожая оптимизация, связанная с возвращаемым из функции значением.
Вы про Return Value Optimization (RVO)? Согласно Вики, эта оптимизация не только в gcc есть, но и в большинстве других компиляторов.
В случае, если выставить это слово перед copy-конструктором, мы получим достаточно забавный запрет неявного приведения типа — запрет приведения к своему типу.

Что ещё забавнее, из-за особенностей синтаксиса С++ вот так: TestClass theTestObject(TestClass()) записать тоже не выйдет, ведь это будет считаться объявлением указателя на функцию и вызовет ошибку:

Мне кажется, у вас есть некоторая путаница с пониманием видов инициализации в C++ (в данном случае direct и copy, инициализация через = в объявлении ведет к copy).
А на счет невозможности написать из-за особенностей синтаксиса — применяйте uniform-инициализацию (TestClass{}), ваш компилятор должен поддерживать такой синтаксис.
Или можно поставить лишнюю пару скобок (для старых компиляторов):
TestClass theTestObject((TestClass()))
    template<typename T_OtherType,
            typename T_OtherHolding,
            typename T_OtherAccess>
    DReference(
            const DReference<T_OtherType, T_OtherHolding, T_OtherAccess> &
                    inLReference) : _holder(NULL), _holding(), _access()
    {
        retain(inLReference._holder);
    }


Это единственный конструктор, предназначеный для копирования DReference?
Для корректной работы умных указателей вам необходимо определить DReference& DReference::operator = (const DReference&), либо удалить его реализацию по-умолчанию — не знаю, сделали вы это или нет. Реализация по-умолчанию в вашем случае приводит к ошибкам.

EDIT: ошибся с веткой немного
Да, когда я писал статью был единственным. Но буквально через несколько дней после отправки на премодерацию я понял как сильно сглупил, добавил его — и одной ошибкой стало меньше.
Перечитал статью внимательнее. Судя по симптомам и лечению, действительно (был) единственный.

ISO IEC 14882-2003 §12.8 Copying class objects [class.copy]
A member function template is never instantiated to perform the copy of a class object to an object of its class type.

Сноска:
106) Because a template constructor is never a copy constructor, the presence of such a template does not suppress the implicit declaration of a copy constructor. Template constructors participate in overload resolution with other constructors, including copy constructors, and a template constructor may be used to copy an object if it provides a better match than other constructors.


ISO IEC 14882-2011 §12.8 Copying class objects [class.copy]
A member function template is never instantiated to produce such a constructor signature.


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

Т.е. нужно явно определять конструктор копирования, что вы в итоге и сделали, но это не «some magic cases», а так и задумано.

А copy-elision тут ни в чём не виновен.
Да, всё верно, спасибо…

В следующий раз когда буду думать плохо о стандарте, буду его внимательнее читать сначала.
Sign up to leave a comment.

Articles