构造函数参数样式
Constructor parameter style
假设我的文件是这样的:
#include <iostream>
#include <string>
using namespace std;
class testclass{
public: string name;
//testclass(const string& sref){
// name = sref;
//}
testclass(string str){
name = str;
}
~testclass(){}
};
int main(){
testclass t1("constStringRef");
cout << t1.name << 'n';
}
给定下面的构造函数调用,构造函数1和构造函数2的区别是什么?
testclass tobj("tmemberstring");
我是这么想的:
我知道通过引用传递意味着您不传递副本,但由于字符串参数首先有一个字符串初始化(在两种情况下都被视为局部变量,我假设),然后在情况1中对它的引用的初始化或在情况2中对新字符串str的复制。最后,两个构造函数都将值复制到成员字符串名称中。如果我的想法是正确的,我将跳过一步(复制到字符串str),它将使用第一个构造函数。
Sidequestions:参数是否存储在堆栈区域?如果是这样,这个特定的字符串引用或任何基本数据类型的引用会使用多少空间?
希望你的建议,提前致谢
回答你的问题最简单的方法是把这两种情况分别分析一下。
testclass(const string& sref)
-
testclass t1("constStringRef");
首先从const char*
创建一个临时的 - 构造函数被调用,临时
string
对象被绑定到构造函数的const string&
参数 -
name
是无用的默认构造,因为您没有使用构造函数的初始化列表(稍后将详细介绍) 调用
string
对象string::operator =
,复制const string&
参数Total: 1 copy.
testclass(string str)
-
testclass t1("constStringRef");
首先从const char*
创建一个临时的 - 构造函数被调用——会发生什么取决于你使用的c++版本:
- c++ 03:临时的
string
对象被复制到构造函数的参数 c++ 11:临时的被移动到构造函数的参数中
string
对象name
是无用的默认构造,因为你没有使用构造函数的初始化列表string::operator =
,复制string
参数总:在c++ 03副本2份,1份c++ 11。
由此,我们可以认为const string&
是更好的。但是这只适用于c++ 03。
c++ 11和移动语义
在c++ 11中,最好(在这种情况下)按值将字符串传递给构造函数,然后将参数移动到类成员中:
testclass(string str){
name = std::move(str);
}
让我们看看现在发生了什么:
-
testclass t1("constStringRef");
首先从const char*
创建一个临时的 - 构造函数被调用,临时的被移动到构造函数的参数 中
-
name
是无用的默认构造,因为你没有使用构造函数的初始化列表 调用 -
string::operator =
,但这次将string
参数移动到
string
对象name
Total: 0 copy!
这对于右值来说都很好,但是对于左值来说仍然成立吗?
string s = "..."; // s has already been constructed some time ago
testclass t1(s); // what happens during this call?
对于接受
const string&
的构造函数(c++ 03和c++ 11):-
s
被绑定到const string&
参数 -
name
是无用的默认构造,因为你没有使用构造函数的初始化列表 调用 -
string::operator =
,复制const string&
参数 - Total: 1 copy.
-
用于获取
string
然后移动它的构造函数(仅在c++ 11中):s
被复制到string
参数-
name
是无用的默认构造,因为你没有使用构造函数的初始化列表 调用 -
string::operator =
,但这次将string
参数移动到name
- Total: 1 copy.
结束
在c++ 03中,无论传递左值还是右值都无关紧要,使用const string&
总是更有效。正如其他人所提到的,您可能希望重载构造函数以接受const char*
参数,从而避免无用的复制。
在c++ 11中,如果您将参数移动到成员变量中,则string
参数与const string&
参数对于左值相同,但对于右值更有效(根本不需要执行复制)。因此,您应该使用按值传递,然后将参数移动到成员变量。
最后但并非最不重要的是,您注意到我坚持使用无用的默认构造name
。要避免这种情况,可以使用构造函数的初始化列表,而不是在构造函数体中使用赋值:
// C++03
testclass(const char* str) : name(str) {} // no copy
testclass(const string& sref) : name(sref) {} // 1 copy
// C++11
testclass(string str) : name(std::move(str)) {} // 1 copy for lvalues,
// no copy for rvalues
在这两种情况下,构造函数都接受std::string
。由于您正在使用字符串字面值(const char*
)调用构造函数,因此将构造一个临时std::string
以调用构造函数。这两种方法的区别在于接下来发生的事情:
在testclass(const string& sref)
的情况下,const
对您刚刚创建的临时string
的引用可以被获取。在第二种情况下,字符串是按值获取的,因此需要创建一个第二个临时值。
- 注意:编译器有时可以优化这第二个临时值。
作为一般的经验法则,我建议尽可能使用const&
。
std::string
,只需通过模板接受字符串字面值:
template <size_t N> testclass(const char (&str)[N])
{
name = str;
}
还要注意,当调用构造函数时,会发生两件事。1)构造name
成员。2)修改name
成员的值;您可以使用初始化列表在一个步骤中初始化和构造name
成员:
template <size_t N> testclass(const char (&str)[N])
:
name (str, N-1) // minus one to not copy the trailing ` `. Optional, depending
{
name = str;
}
首先,最好以"std::endl"而不是"'n'"结束您的流行。一个构造函数需要一个引用,另一个需要一个值,但是你传递的是一个值为"const char*"的C-String。第三:在调用构造函数代码之前初始化成员。我推荐以下内容:
testclass(const char* name) : name(name) {};
我知道通过引用传递意味着你不传递一个副本
是的,所以你通常应该选择testclass::testclass(const std::string&)
,因为它避免了复制
但是由于string参数首先有一个string初始化
是的,要么创建一个临时字符串并作为const ref传递,要么直接创建实参。
还有另一个字符串:你的name
成员是默认初始化的,只是因为你没有使用初始化列表。:
testclass::testclass(const std::string &s) : name(s) {}
直接初始化name
,不需要先默认初始化它,然后在构造函数体中修改它。
附加问题:参数是否存储在堆栈区域?
参数可以保存在堆栈中,也可以保存在寄存器中,或者以编译器发现的符合标准的任何其他方式保存。这是实现细节。
…如果是这样,这个特定的字符串引用或任何基本数据类型的引用会使用多少空间?
一般来说,引用可能不超过指针的大小(并且可能完全省略)。
你没有考虑的事情是std::string
拥有一个动态分配的字符数组副本,所以你通过值传递的每个std::string
可能会执行一个动态分配,然后在它超出范围时取消分配。(有些编译器可能会通过引用计数来避免这种情况,但我们会回到实现细节)。
- C++中的高效循环缓冲区,它将被传递给C样式数组函数参数
- 将有状态的 lambda 传递到 C 样式函数中,而无需上下文参数
- 解压缩 C 样式数组以及C++中的参数包
- C++ C 样式数组作为语法错误的参数
- 限制C++中允许的模板参数是否被认为是不良样式?
- C 样式将此或shared_from_this作为函数参数
- 如何将初始值设定项与右值引用参数一起使用 // 为什么不能使用另一个 C 样式数组变量初始化 C 样式数组
- Qt样式表和"一个参数"问题
- 为什么我可以通过这样的字符串参数?这种样式安全吗?
- C 函数对象模板参数扣除样式
- 具有列表参数C++11/C++14样式的求和函数
- C++,哪种参数样式更好,通过复制还是通过常量引用
- C/C++样式--修改函数参数
- C++样式:在构造函数主体中使用参数或成员
- 向 C 样式可变参数列表添加额外的参数
- C++ 传递 C 样式字符串作为参数
- 构造函数参数样式
- 为通过引用设置参数的函数命名的样式
- CreateWindow()样式参数被忽略
- 函数调用参数中的构造函数样式转换