const T& val = T()
以下是vector类模拟实现中 resize() 部分代码:
cpp
/* resize */
// val不能给0,因为不知道T的类型,所以给一个T的缺省值
void resize(size_t n, const T& val = T())
{
// 缩小size
if (n < size())
_finish = _start + n;
else // 增大size
{
// 假如需要扩容
if (n > capacity())
{
reserve(n);
}
while (_finish < _start + n)
{
*_finish = val;
++_finish;
}
}
}
const T& val = T() 的含义
这行代码实际上包含了三个关键概念:
1. T() - 值初始化
-
T()表示创建一个类型为T的临时对象,并使用值初始化 -
对于内置类型(如
int,double,指针等),T()会将其初始化为零值:-
int()→0 -
double()→0.0 -
char()→'\0' -
指针()→nullptr
-
-
对于类类型,
T()会调用默认构造函数
2. const T& - 常量引用
-
使用常量引用可以避免不必要的对象拷贝
-
常量引用可以绑定到临时对象(如
T()创建的对象)
3. = T() - 默认参数
- 这是函数的默认参数,如果调用时不提供这个参数,就使用
T()作为默认值
为什么要这样设计?
通用性
由于 vector 是模板类,需要处理任意类型 T:
-
如果是
vector<int>,T()就是0 -
如果是
vector<string>,T()就是空字符串 -
如果是
vector<MyClass>,T()会调用MyClass的默认构造函数
示例代码:
cpp
vector<int> v1;
v1.resize(10); // 使用默认值 int() = 0,所有新元素初始化为0
vector<double> v2;
v2.resize(5); // 使用默认值 double() = 0.0
vector<string> v3;
v3.resize(3); // 使用默认值 string() = 空字符串// 也可以显式指定值
v1.resize(15, 100); // 新元素初始化为100
v3.resize(5, "hello");// 新元素初始化为"hello"
为什么不能直接用 0?
为什么不能写成 void resize(size_t n, const T& val = 0)?
这是因为:
-
类型不匹配:如果
T是string,0不是有效的字符串值 -
缺乏通用性:不是所有类型都能从
0构造 -
编译错误:对于不能从
0转换的类型,代码无法编译
而 T() 为每种类型提供了最合适的"零值"或默认值,保证了代码的通用性和类型安全。
总结
const T& val = T() 是一个巧妙的设计:
-
通用:适用于任何类型
T -
高效:使用引用避免拷贝
-
安全:提供类型安全的默认值
-
灵活:允许调用者提供自定义值,也有合理的默认值
这种写法在STL和现代C++库中非常常见,是编写通用模板代码的重要技巧之一。