[g++] баг или стандарт?

mirt1971

Сегодня ночью столкнулся с такой штукой: есть у меня шаблон класса AutoPtr:


template < class P >
class AutoPtr
{
public:
inline AutoPtr( P* p = 0 ) throw :
d_p( p )
{
__printf( "1\n" );
}
template< class Q >
inline AutoPtr( const AutoPtr< Q >& ap ) throw :
d_p( ap.release )
{
__printf( "2\n" );
}
..............
inline P* release throw
{
__printf( "13\n" );
P* ret = d_p; d_p = 0;

return ret;
}


Очевидно что конструктор копий некорректен, он не должен даже компилироваться(передается константная ссылка, и у нее вызывается неконстантный метод release.
Как вы думаете что происходит во время компиляции/выполнения такой функции?


AutoPtr<A> func
{
return AutoPtr<A>( new A );//это конечно модельный пример
}


Вместо того чтобы сказать что у меня неправильный конструктор, g++ создает конструктор по умолчанию и использует его. После того как я убрал const, все заработало. Так вот, хотелось бы понять, это баг или поведение, требуемое стандартом?

daru

Маза: компилятор должен пропускать шаблоны, которые приводят к ошибкам компиляции.
В частности, он мог скипнуть твой конструктор от AutoPtr<Q>. Получить при этом отсутствие конструктора копирования и сгенерить его самому.
P.S. Не знаю, что сказал бы стандарт, но компилятор vc7 ведет себя точно также.

freezer

ошибка должна происходить при инстанциировании шаблона

mirt1971

Я тоже так думаю. Но почему я тогда получаю такое странное поведение? Вот что непонятно. Грубо говоря, кто неправ?

mirt1971

Имхо это неправильно. Он должен сказать что я дурак и код у меня дурацкий, а не пропускать его молча.

rosali

После того как я убрал const, все заработало

Тут?
inline AutoPtr( const AutoPtr< Q >& ap ) ...

А что, если const-а нету, то это тоже считается конструктором копий?!

mirt1971

Ну это не есть конструктор копий... Просто я его так назвал, так как сигнатуры схожи... А вообще говоря AutoPtr невозможно СКОПИРОВАТЬ, на то он и AutoPtr

stat6535144

IMHO - этот код верен
-----------------------
inline AutoPtr( const AutoPtr< Q >& ap ) throw :
d_p( ap.release )
{
printf( "2\n" );
}
------------------------
Этот конструктор создает объект AutoPtr и не кидает исключений/ошибок компиляции когда объекту типа P можно присвоить объект типа Q
Такой же(ОЧЕНЬ похожий) пример обсуждался в Страуструпе в разделе про шаблоны.
ЗЫ: Исходя из названия класса - зачем создавать велосипед, почему не воспользоваться стандартной библиотекой boost? (Без обид - если автор хочет этого, я не против)

mirt1971

Этот код неверен. Посмотри ap.release - это неконстантный метод, вызываемый у константной ссылки.
PS: Использовать буст ради одного шаблона? Ну ну.

daru

Я имел в виду следующее (из документации к boost):
Sensible operation of template function overloading in C++ relies on the SFINAE (substitution-failure-is-not-an-error) principle: if an invalid argument or return type is formed during the instantiation of a function template, the instantiation is removed from the overload resolution set instead of causing a compilation error. The following example, demonstrates why this is important:
int negate(int i) { return -i; }
template <class F>
typename F::result_type negate(const F& f) { return -f; }
Suppose the compiler encounters the call negate(1). The first definition is obviously a better match, but the compiler must nevertheless consider (and instantiate the prototypes) of both definitions to find this out. Instantiating the latter definition with F as int would result in:
int::result_type negate(const int&);
where the return type is invalid. If this was an error, adding an unrelated function template (that was never called) could break otherwise valid code. Due to the SFINAE principle the above example is not, however, erroneous. The latter definition of negate is simply removed from the overload resolution set.

Думаю, что для конструкторов действует сходная логика. Ботать стандарт ломает :-)

daru

А, не, кстати, тут все проще:
Твой конструктор не является конструктором копии с точки зрения компилятора C++ даже если Q == T. Так поэтому создается конструктор по умолчанию.

mirt1971

C точки зрения компилятора первая версия очень даже является конструктором копий. Без const - не является. Мне кажется верным именно первое объяснение. Спасибо за цитату
Оставить комментарий
Имя или ник:
Комментарий: