С++ всегда использует явный конструктор

После прочтения следующего блога:

http://xania.org/200711/ambiguous-overloading

Я начал спрашивать себя: «Не следует ли мне всегда явно определять мои конструкторы?»

Поэтому я начал читать больше, чем узнал эту статью:

http://www.sjbrown.co.uk/2004/05/01/always-use-explicit/

Который показывает другой пример, а также объясняет его мысли, стоящие за ним. Но, конечно, это мысли одного блоггера.

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


person oopsi    schedule 15.09.2012    source источник
comment
Этот вопрос не является конструктивным, потому что он требует мнения. Вы должны изменить его, чтобы вместо этого запрашивать неопровержимые факты, например, каковы недостатки использования конструкторов, которые компилятор создает автоматически, если таковые имеются, или каковы правила, чтобы решить, когда мне нужно явно определить мои конструкторы?   -  person Sergey Kalinichenko    schedule 15.09.2012
comment
хотя я согласен с dasblinkenlight, я бы сказал, да, всегда используйте явное. это усложняет использование вашего класса (случайно) неправильным образом, и это хорошо   -  person stijn    schedule 15.09.2012
comment
Вопрос, заданный oopsi, очень полезен, и я действительно не могу понять, почему некоторые люди так хотят закрыть информативный вопрос. Я твердо уверен, что комитет Stackoverflow должен пересмотреть свою политику и убедиться, что ценные вопросы не закрыты только потому, что некоторые люди с небольшими баллами имеют на это право. Я думаю, что вся цель существования форума состоит в том, чтобы делиться знаниями, но, закрывая его, мы не помогаем ему.   -  person samprat    schedule 17.08.2014


Ответы (1)


Традиционно считается, что конструкторы, принимающие один параметр (явно или эффективно за счет использования параметров по умолчанию), должны быть помечены explicit, если только они не определяют преобразование (std::string может быть преобразовано из const char*, что является одним из примеров последнего ). Вы сами выяснили причины в том, что неявные преобразования действительно могут сделать жизнь сложнее, чем она должна быть.

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

Хотя может показаться, что маркировка всех других типов конструкторов explicit не повредит, я бы возражал против этого. Потому что, хотя explicit не влияет на конструктор, принимающий несколько аргументов в C++03, он влияет на C++11. Чтобы поместить это в код:

struct foo {
    explicit foo(int i);
    foo(int i, int j);
    explicit foo(int i, int j, int k);
};

foo make_foo()
{
    /* Not C++11-specific: */
    // Error: no conversion from int to foo
    return 42;

    // Okay: construction, not conversion
    return foo(42);

    // Okay: constructions
    return foo(42, 42);
    return foo(42, 42, 42);

    /* C++11 specific: */
    // Error: no conversion from int to foo
    return { 42 };

    // Not an error, not a conversion
    return { 42, 42 };

    // Error! Constructor is explicit
    return { 42, 42, 42 };
    // Not an error, direct-initialization syntax
    return foo { 42, 42, 42 };
}

Лично я считаю излишне многословным, что в функции, которая возвращает foo, я должен явно возвращать foo { 42, 42, 42 }. Я не понимаю, от чего меня защищает explicit. Я действительно хочу, чтобы синтаксис { initializers... } означал «создать объект из заданных инициализаторов», а explicit мешает этому, спасая меня от ничего. (Поскольку { i } действительно сводится к i в контексте инициализации копирования — в большинстве случаев — я с радостью откажусь от этого.)

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

person Luc Danton    schedule 15.09.2012
comment
+1 за информацию о С++ 11, о которой я понятия не имел. - person Tomek; 15.09.2012
comment
Necro'ing, но как насчет конструкторов со всеми необязательными параметрами, кроме первого, например foo(int a,int b=0, int c=0). Они по-прежнему допускают неявное преобразование из int. Лучше пометить их явными? - person dureuill; 05.04.2017
comment
@dureuill Это ваш выбор, это ваш выбор как автора класса, хотите ли вы, чтобы конструкция была явной или нет. Разница между параметрами по умолчанию заключается в том, что один и тот же конструктор выполняет работу по построению с одним, двумя или тремя параметрами. Либо все эти формы конструкции являются явными, либо ни одна из них. Для более детального управления вам придется разделить конструктор на большее количество перегрузок. - person Luc Danton; 05.04.2017