修改复制构造函数的“ explicit ”关键字可能会导致问题。\n作为函数参数传递的对象特别容易受到这些问题的影响。
\n这是我的代码:
\n#include <iostream>\n#include <string>\n\nclass Pig{\npublic:\n std::string _name;\npublic:\n Pig(std::string n) : _name(n) {}\n //~Pig() = default;\n explicit Pig(const Pig &other) {\n std::cout << "copy ctor!" << std::endl;\n this->_name = other._name;\n }\n};\n\nvoid show(Pig p) {\n std::cout << p._name << std::endl;\n}\n\nint main() {\n Pig pig{std::string("hello")};\n show(Pig{pig}); // no pass\n // show(Pig(pig)); // no pass\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n编译器版本:g++(Ubuntu 9.4.0-1ubuntu1~20.04.1)9.4.0。
\n上面提到的代码不能用c++14 或更低版本编译,\n但用c++17 及更高版本编译成功。
\n这是编译器的错误:
\ntest.cpp: In function \xe2\x80\x98int main()\xe2\x80\x99:\ntest.cpp:22:7: error: cannot …Run Code Online (Sandbox Code Playgroud) 为什么g_Fun()执行return temp它会调用复制构造函数?
class CExample
{
private:
int a;
public:
CExample(int b)
{
a = b;
}
CExample(const CExample& C)
{
a = C.a;
cout<<"copy"<<endl;
}
void Show ()
{
cout<<a<<endl;
}
};
CExample g_Fun()
{
CExample temp(0);
return temp;
}
int main()
{
g_Fun();
return 0;
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试编写自己的智能指针(C ++ 11)并使用一个问题进行堆栈,可以通过下一个示例进行解释:
#include <iostream>
template<typename T_Type>
class TestTemplateClass {
private:
T_Type _state;
public:
TestTemplateClass() : _state() {
std::cout << "Default constructor" << std::endl;
}
TestTemplateClass(int inState) : _state(inState) {
std::cout << "State constructor" << std::endl;
}
template<typename T_OtherType>
TestTemplateClass(const TestTemplateClass<T_OtherType> &inValue) {
std::cout << "Template-copy constructor" << std::endl;
}
template<typename T_OtherType>
void operator = (const TestTemplateClass<T_OtherType> &inValue) {
std::cout << "Operator" << std::endl;
}
~TestTemplateClass() {
std::cout << "Destructor" << std::endl;
}
};
TestTemplateClass<int> createFunction() {
return TestTemplateClass<int>();
} …Run Code Online (Sandbox Code Playgroud) (这个问题的灵感来自Nicolai Josuttis的CppCon 2017演讲.)
考虑以下源文件(对于对象,而不是完整的程序):
#include <string>
class C {
std::string s_;
public:
C(std::string s) : s_(s) { };
void bar();
};
void foo() {
std::string hello { "The quick brown fox jumped over the lazy dog" };
C c { hello };
c.bar();
}
Run Code Online (Sandbox Code Playgroud)
即使使用-O2(甚至使用-O3),似乎字符串构造函数被调用三次.具体而言,s构造,仅用于构造s_,然后被破坏.我的问题:
s_从ctor的参数构造,而不是构造s?s_从s,看到后者是如何闲置?s构造正确,编译器不能避免构造hello,看看它没有其他用途吗?或者至少离开它?考虑以下代码:
#include <iostream>
struct S
{
S(std::string s) : s_{s} { std::cout << "S( string ) c-tor\n"; }
S(S const&) { std::cout << "S( S const& ) c-tor\n"; }
S(S&& s) { std::cout << "S&& c-tor\n"; s_ = std::move(s.s_); }
S& operator=(S const&) { std::cout << "operator S( const& ) c-tor\n"; return *this;}
S& operator=(S&& s) { std::cout << "operator (S&&)\n"; s_ = std::move(s.s_); return *this; }
~S() { std::cout << "~S() d-tor\n"; }
std::string s_;
};
S foo() { …Run Code Online (Sandbox Code Playgroud) 对复制省略的解释指出:
在以下情况下,即使复制/移动构造函数和析构函数具有明显的副作用,也要求编译器忽略类对象的复制和移动构造。这些对象直接构造到存储中,否则会将它们复制/移动到其中。复制/移动构造函数不需要存在或不可访问,因为语言规则可确保不会进行复制/移动操作,即使在概念上也是如此:
在return语句中,当操作数是与函数返回类型相同的类类型(忽略cv限定)的prvalue时:
T f(){返回T(); }
f(); //仅调用T的默认构造函数
我的问题是,为什么下面的代码不能编译:
#include <mutex>
std::mutex createMutex()
{
return std::mutex();
}
int main()
{
auto mutex = createMutex();
}
Run Code Online (Sandbox Code Playgroud)
lambda 表达式(作为返回值)中的按值捕获 ( [x]) (或 C++14 移动捕获[x = std::move(x)])中的复制(移动)构造是否可能(或保证)被省略?
auto param_by_value(Widget w) {
// manipulating w ...
return [w] { w.doSomeThing(); };
}
auto param_by_move(Widget w) {
// manipulating w ...
return [w = std::move(w)] { w.doSomeThing() };
}
auto local_by_value() {
Widget w;
// manipulating w ...
return [w] { w.doSomeThing(); };
}
auto local_by_move() {
Widget w;
// manipulating w ...
return [w = std::move(w)] { w.doSomeThing() };
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:
w可能(甚至保证)被省略?(我记得显式std::move有时会阻止复制省略,并且参数的复制/移动是不可能被省略的。) …标准库实用程序declval被定义为:
template<class T> add_rvalue_reference_t<T> declval() noexcept;
Run Code Online (Sandbox Code Playgroud)
在这里添加右值引用似乎是一个好主意,如果您考虑一下C++11 中引入的语言:返回值涉及一个临时值,该值随后被移出。现在C++17引入了保证复制省略,这不再适用。正如cppref所说:
纯右值和临时值的 C++17 核心语言规范与早期 C++ 修订版的核心语言规范根本不同:不再有临时值可以复制/移动。描述 C++17 机制的另一种方法是“非物化值传递”:返回和使用纯右值,而不会物化临时值。
这对其他以declval. 看看这个例子(在Godbolt.org上查看):
#include <type_traits>
struct Class {
explicit Class() noexcept {}
Class& operator=(Class&&) noexcept = delete;
};
Class getClass() {
return Class();
}
void test() noexcept {
Class c{getClass()}; // succeeds in C++17 because of guaranteed copy elision
}
static_assert(std::is_constructible<Class, Class>::value); // fails …Run Code Online (Sandbox Code Playgroud) 我有这段代码:
#include <iostream>
#include <vector>
using namespace std;
class Foo{
public:
Foo() noexcept {cout << "ctor" << endl;}
Foo(const Foo&) noexcept {cout << "copy ctor" << endl;}
Foo(Foo&&) noexcept {cout << "move ctor" << endl;}
Foo& operator=(Foo&&) noexcept {cout << "move assn" << endl; return *this;}
Foo& operator=(const Foo&) noexcept {cout << "copy assn" << endl; return *this;}
~Foo() noexcept {cout << "dtor" << endl;}
};
int main()
{
Foo foo;
vector<Foo> v;
v.push_back(std::move(foo));
// comment the above 2 lines …Run Code Online (Sandbox Code Playgroud) 以下来自我的C++书籍的引文:
当我们使用直接初始化时,我们要求编译器使用普通函数匹配来选择与我们提供的参数最匹配的构造函数.当我们使用复制初始化时,我们要求编译器将右侧操作数复制到正在创建的对象中,必要时转换该操作数.
对我来说,这个粗体位会产生一些模糊性.它使得听起来像右手操作数被转换为类类型,然后使用复制构造函数,例如;
string s = "hello";
Run Code Online (Sandbox Code Playgroud)
会成为...
string s = string("hello");
Run Code Online (Sandbox Code Playgroud)
它使用复制构造函数.如果这是真的那么我的测试程序;
#include <iostream>
using namespace std;
class A{
public:
A(const A& b): data(b.data) { cout << "The first way" << endl;}
A(const char* c): data(c) { cout << "The second way" << endl;}
string data;
};
int main(){
A first("hello");
A second = "sup";
}
Run Code Online (Sandbox Code Playgroud)
应该产生"第二种方式,第二种方式,第一种方式".然而它反而打印出"第二种方式,第二种方式".从这里我可以得出结论它是使用const char*构造函数而不是复制构造函数.我会好的,除非后来说......
在复制初始化期间,允许编译器(但没有义务)跳过复制/移动构造函数并直接创建对象.也就是说,允许编译器重写
Run Code Online (Sandbox Code Playgroud)string null_book = "9-999-99999-9";成
Run Code Online (Sandbox Code Playgroud)string null_book("9-999-99999-9");但是,即使编译器省略了对复制/移动构造函数的调用,复制/移动构造函数也必须存在,并且必须在程序中的该点可访问(例如,非私有).
我不确定为什么复制构造函数甚至需要在这些示例中提及,否则
string null_book = "9-999-99999-9"
Run Code Online (Sandbox Code Playgroud)
总是隐含地意味着仍然使用const char*构造函数?实际上,我不需要定义复制构造函数以使上述工作正常.但是,如果我将"const A&"构造函数设置为私有(其他公共),那么我的程序将无法运行.为什么必须为不涉及它的隐式转换定义复制构造函数?什么构造函数"string null_book …
c++ copy-constructor implicit-conversion copy-initialization copy-elision