Jens Asked:2020-11-17 02:46:50 +0000 UTC2020-11-17 02:46:50 +0000 UTC 2020-11-17 02:46:50 +0000 UTC 复制和移动构造函数的“显式” 772 是否有必要(如果需要,在什么情况下)将复制和移动构造函数指定为explicit?我在代码中看到了这一点,并不太明白。explicit帮助我们避免的不必要的隐式转换在哪里? c++ 4 个回答 Voted Best Answer ixSci 2020-11-17T14:47:28Z2020-11-17T14:47:28Z 这个问题的答案很简单:在explicit需要的地方需要它,在不需要的地方,也不需要它。有一个常见的建议是,所有接受一个参数的构造函数都应该用 标记explicit,以避免在创建不明显的情况下意外创建类对象。例如,我们有一个函数void someFun(const std::shared_ptr<int[]>&),我们很偶然地像这样使用它: int* array = new int[55]; someFun(array); delete[] array; 如果没有构造函数std::shared_ptr,explicit那么代码将成功编译,在第三行我们将得到未定义的行为。但是由于 构造函数std::shared_ptr被标记,因为explicit我们不会偶然遇到这种情况。因此,它explicit旨在消除随机错误。 至于explicit复制构造函数:我从来没有见过这样的东西,我想不出为什么需要它。如果我们想禁止复制,那么我们需要完全删除它,如果我们不想这样做,那么为什么只允许一组狭窄的句法选项来加入轮辐,使用它可以复制一个目的? 一个例子是下面的代码: #include <iostream> #include <string> 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,则指示其显式使用的示例将停止工作。复制构造函数也是如此。 Андрей Чивесон 2020-11-17T04:00:56Z2020-11-17T04:00:56Z 显式关键字将避免可能导致隐式错误的意外类型转换。 例如:您有一个带有构造函数的类,该构造函数MyString(int size)创建一个大小为大小的字符串。还有一种方法print(const MyString&),当你调用时,print(3)你可以期待一个 print("3") 调用,但实际上你会得到一个 3 个字符的空字符串。 可以在这里找到一个好的详细答案。 Andrey Burmagin 2022-01-06T21:10:26Z2022-01-06T21:10:26Z 将复制构造函数声明为explicit有助于避免错误地切片,尽管它不允许当前类型的所有按值传递参数。有关这方面的更多信息,请参见 Sutter 和 Alexandrescu 所著的“C++ 中的编程标准”一书的第 54 段。 Виталий 2020-11-17T04:03:36Z2020-11-17T04:03:36Z 如果您稍后定义或显式删除复制和移动运算符,则不需要这样做。
这个问题的答案很简单:在
explicit需要的地方需要它,在不需要的地方,也不需要它。有一个常见的建议是,所有接受一个参数的构造函数都应该用 标记explicit,以避免在创建不明显的情况下意外创建类对象。例如,我们有一个函数void someFun(const std::shared_ptr<int[]>&),我们很偶然地像这样使用它:如果没有构造函数
std::shared_ptr,explicit那么代码将成功编译,在第三行我们将得到未定义的行为。但是由于 构造函数std::shared_ptr被标记,因为explicit我们不会偶然遇到这种情况。因此,它explicit旨在消除随机错误。至于
explicit复制构造函数:我从来没有见过这样的东西,我想不出为什么需要它。如果我们想禁止复制,那么我们需要完全删除它,如果我们不想这样做,那么为什么只允许一组狭窄的句法选项来加入轮辐,使用它可以复制一个目的?一个例子是下面的代码:
如果您在代码中将构造函数标记为
explicit,则指示其显式使用的示例将停止工作。复制构造函数也是如此。显式关键字将避免可能导致隐式错误的意外类型转换。
例如:您有一个带有构造函数的类,该构造函数
MyString(int size)创建一个大小为大小的字符串。还有一种方法print(const MyString&),当你调用时,print(3)你可以期待一个 print("3") 调用,但实际上你会得到一个 3 个字符的空字符串。可以在这里找到一个好的详细答案。
将复制构造函数声明为
explicit有助于避免错误地切片,尽管它不允许当前类型的所有按值传递参数。有关这方面的更多信息,请参见 Sutter 和 Alexandrescu 所著的“C++ 中的编程标准”一书的第 54 段。如果您稍后定义或显式删除复制和移动运算符,则不需要这样做。