Надо ли (и если да, то в каких случаях) указывать конструкторы копирования и перемещения как explicit? Видел такое в коде и не совсем понял. Где ненужное неявное преобразование, которое explicit помогает нам избежать?
Ответ
Ответ на этот вопрос прост: explicit нужен там, где он нужен, а где не нужен — там не нужен. Есть распространённый совет, что все конструкторы, что принимают один аргумент должны быть помечены explicit, во избежание случайного создания объектов класса там, где их создание не очевидно. К примеру, есть у нас функция void someFun(const std::shared_ptr
int* array = new int[55];
someFun(array);
delete[] array;
Если бы конструктор std::shared_ptr не был explicit, то код бы успешно скомпилировался и на третьей строчке мы бы получили неопределённое поведение. Но т.к. конструктор std::shared_ptr помечен как explicit мы не получим такую ситуацию случайно. Таким образом, explicit призван исключить случайные ошибки.
Что касается explicit конструктора копирования: ни разу не видел такого и не могу придумать, зачем такой может быть нужен. Если мы хотим запретить копирование, то нужно удалить его вообще, если не хотим, то зачем вставлять палки в колёса разрешая лишь узкий набор синтаксических вариантов, используя которые можно будет скопировать объект?
В качестве примера можно привести следующий код:
#include
using namespace std;
class MeClass
{
public:
MeClass(size_t idx, const string& tag = "") :
m_Idx{idx},
m_Tag{tag}
{
}
MeClass(const MeClass& rhs):
m_Idx{rhs.m_Idx},
m_Tag{rhs.m_Tag}
{
}
private:
size_t m_Idx;
string m_Tag;
};
MeClass explicitReturn()
{
// Явный вызов конструктора
// Неявный вызов конструктора копирования
// move нужен исключительно для исключения C++17 RVO
return move(MeClass{2, "meTag"});
}
MeClass implicitReturn()
{
// Неявный вызов конструктора
// Неявный вызов конструктора копирования (до C++17)
return {3, "meaTag"};
}
void funForFun(const MeClass& me)
{
}
int main()
{
// Явный вызов конструктора
MeClass me1{1};
// Неявный вызов конструктора
MeClass me2 = 2;
// Неявный вызов конструктора копирования
auto me3 = me1;
// Явный вызов конструктора копирования
auto me4{me1};
// Неявный вызов конструктора
funForFun(2);
funForFun({3});
// Явный вызов конструктора
funForFun(me1);
};
Если пометить в коде конструктор как explicit, то перестанут работать примеры, где указано явное его использование. То же самое с конструктором копирования.
Комментариев нет:
Отправить комментарий