为什么要使用函数而不是引用成员
Why use a function rather than a reference to member?
我只是在测试中查看了一些代码,并注意到类似于以下内容:
template<typename T>
class example{
public:
example(T t): m_value{t}{}
const T &value = m_value;
private:
T m_value;
};
我以前没见过这个。我以前使用过的几乎每一个API或库都定义了一个函数,该函数返回这样的成员变量,而不是对它的恒定引用:
template<typename T>
class example{
public:
example(T t): m_value{t}{}
const T &value() const{
return m_value;
}
private:
T m_value;
};
为什么第一种方式不那么常见?缺点是什么?
返回适当引用的(内联)函数更好的原因有几个:
-
引用将需要每个对象中的内存(通常与指针的数量相同)
-
引用通常与指针具有相同的对齐方式,因此导致周围对象可能需要更高的对齐方式并因此浪费更多的内存
-
初始化引用需要(少量)时间
-
具有引用类型的成员字段将禁用默认的复制和移动分配运算符,因为引用不可重新放置
-
具有引用类型的成员字段将导致自动生成的默认复制和移动构造函数不正确,因为它们现在将包含对其他对象成员的引用
-
函数可以进行额外的检查,如在调试构建中验证不变量
请注意,由于内联,函数通常不会产生任何额外的成本,除了可能稍大的二进制文件。
封装。
对于面向对象编程纯粹主义者来说,m_value
是一个实现细节。example
类的使用者应该能够使用一个可靠的接口来访问value()
,而不应该依赖于example
如何确定它。example
的未来版本(或复杂的模板专用化)可能希望在返回value()
之前使用缓存或日志记录;或者可能由于存储器约束而需要动态地计算CCD_ 7。
如果您最初不使用访问器函数,那么如果您以后改变主意,那么使用example
的所有内容可能都必须更改。这会带来各种各样的浪费和漏洞。通过提供类似value()
的访问器,可以更容易地将其抽象一级。
另一方面,有些人对这些OOP原则并不那么严格,只是喜欢编写高效易读的代码,在重构发生时进行处理。
第一个选项需要额外的内存,就像指针一样。
如果你这样做:
inline const T& value() const{
return m_value;
}
在不需要额外内存的情况下,您可以获得与第一种方法相同的好处。
此外,由于第一种方法需要C++11,因此人们使用它的可能性较小。
返回常量引用的常规用法:
在创建或销毁副本成本高昂的情况下,返回常量引用是很常见的
一般来说,规则是:如果传递和使用引用比复制更昂贵,不要这样做。如果没有人要求你提供子对象,通常甚至是不可能的
否则,返回常量引用是有效的性能优化,这对行为良好的源代码是透明的
许多模板代码即使在上面的测试没有指示的地方也会返回常量引用,只是为了平等对待所有专业化,因为函数非常小,而且几乎可以保证内联。
现在,对于你好奇的发现(从未见过它的样子):
+不需要访问器函数(不过,这是蹩脚的,无论如何都会编译出来)
-对象更大(引用通常需要与指针一样多的空间)
-由于上述原因,可能需要更好的对齐
-没有神奇的成员函数,因为编译器不知道如何复制引用
-对于调试生成,不能添加其他检查。
相同的外观&感觉没有附带损害可以像这样实现btw(只有额外的调试检查是不可能的):
template<typename T>
struct example {
example(T t): value{t}{}
union{
const T value;
struct{
private:
T value;
friend class example<T>;
} _value;
};
};
- 具有引用成员的结构是否具有唯一的对象表示形式
- 初始化右值引用成员
- C++通过绑定到引用成员而缩短临时变量寿命?
- C++为具有引用成员变量的类创建复制构造函数
- 常量和引用成员函数限定符
- C++将引用成员绑定到构造函数参数
- 如果包含引用成员的类中缺少原始变量,为什么它仍然可以访问?
- 初始化指针或引用成员变量以指向另一个成员
- 将常量引用成员设置为临时变量是否安全
- 对象超出范围后,引用成员设置为 0
- 复制构造函数初始化初始化列表中的引用成员会导致指针悬空
- 使用默认构造函数引用成员变量初始化错误
- 如何从派生类访问引用成员变量?
- Visual Studio 2017 允许在构造函数中使用自身初始化引用成员.真的是合法的C++吗?
- 为什么当类具有引用成员时C++编译器不删除复制构造函数
- 引用成员到构造函数参数按值传递
- 在执行不平凡的构造函数之前引用成员
- 具有引用成员变量的多态性
- 从按值构造函数参数初始化的引用成员
- 深度复制包含引用成员(C++)的结构