英文:
How does the 'explicit' keyword affect C++ copy constructors and function parameters?
问题
The "explicit" 关键字用于修改复制构造函数可能会引发问题。作为函数参数传递的对象特别容易受到这些问题的影响。
这里是我的代码:
#include <iostream>
#include <string>
class Pig{
public:
std::string _name;
public:
Pig(std::string n) : _name(n) {}
//~Pig() = default;
explicit Pig(const Pig &other) {
std::cout << "copy ctor!" << std::endl;
this->_name = other._name;
}
};
void show(Pig p) {
std::cout << p._name << std::endl;
}
int main() {
Pig pig{std::string("hello")};
show(Pig{pig}); // 不通过
// show(Pig(pig)); // 不通过
return 0;
}
编译器版本:g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0。
上述提到的代码在c++14或更低版本下无法编译,但在c++17及更高版本下可以成功编译。
这里是编译器的错误:
test.cpp: In function ‘int main()’:
test.cpp:22:7: error: cannot convert ‘Pig’ to ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’}
22 | show(Pig{pig}); // 不通过
| ^~~~~~~~
| |
| Pig
- 我知道如何使用 explicit,并希望显式调用复制构造函数以使其工作。
提前感谢您的帮助!
我尝试使用c++14和c++17编译。
英文:
The "explicit" keyword to modify the copy constructor can cause problems.
Objects passed as function parameters are particularly susceptible to these issues.
here are my codes:
#include <iostream>
#include <string>
class Pig{
public:
std::string _name;
public:
Pig(std::string n) : _name(n) {}
//~Pig() = default;
explicit Pig(const Pig &other) {
std::cout << "copy ctor!" << std::endl;
this->_name = other._name;
}
};
void show(Pig p) {
std::cout << p._name << std::endl;
}
int main() {
Pig pig{std::string("hello")};
show(Pig{pig}); // no pass
// show(Pig(pig)); // no pass
return 0;
}
compiler version: g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0.
The code mentioned above does not compile with c++14 or lower versions,
but compiles successfully with c++17 and later versions.
here are the compiler's errors:
test.cpp: In function ‘int main()’:
test.cpp:22:7: error: cannot convert ‘Pig’ to ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’}
22 | show(Pig{pig}); // 不通过
| ^~~~~~~~
| |
| Pig
- I am aware of how to use explicit and I would like to call the copy constructor explicitly in order to make it work.
Thanks in advance!
I tried compiling with c++14 and c++17.
答案1
得分: 5
Prior C++17:
在C++17之前的问题是,当将参数Pig{pig}
传递给show
函数时,会出现参数的概念复制。也就是说,show
函数的名为p
的参数是从传递的参数Pig{pig}
进行复制初始化,由于复制构造函数标记为explicit
,因此会导致所述错误。
这可以从复制初始化中看出:
在以下情况下执行复制初始化:
- 将参数按值传递给函数。
(emphasis mine)
C++17:
另一方面,从C++17开始,prvalue Pig{pig}
会直接构造到变量p
的存储中。也就是说,从C++17开始,不会有参数的概念复制,因此不需要复制构造函数是非显式的等等。
从C++17开始,我们有强制性复制省略:
在以下情况下,即使复制/移动构造函数和析构函数具有可观察的副作用,编译器也必须省略类对象的复制和移动构造,对象将直接构造到否则将其复制/移动到的存储中。复制/移动构造函数不需要存在或可访问:
(emphasis mine)
请注意,Pig{pig}
是一个prvalue,因此上述内容适用,并且复制构造函数不需要存在或可访问(可以是显式的)。
英文:
<h4> Prior C++17</h4>
The problem is that prior to C++17, there will be a conceptual copy of the argument Pig{pig}
when passing it as an argument to the show
function. That is, the parameter named p
of the show
function is copy initialized from the passed argument Pig{pig}
and since the copy ctor is marked explicit
this gives you the mentioned error.
This can be seen from copy initialization:
> Copy initialization is performed in the following situations:
> * When passing an argument to a function by value.
(emphasis mine)
<h4>C++17</h4>
OTOH starting with C++17 the prvalue Pig{pig}
is constructed directly into the storage for p
. That is, there is no conceptual copy of the argument from C++17 and therefore no need for the copy ctor to be non-explicit etc.
From C++17 we have mandatory copy elision:
> Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible:
>
> * In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:
(emphasis mine)
Note that Pig{pig}
is a prvalue and so the above applies and the copy constructor doesn't need to be present or accessible(and it can be explicit).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论