我注意到我通常使用常量引用作为返回值或参数。我认为原因是它的工作原理与在代码中使用非引用几乎相同。但它肯定会占用更多空间,并且函数声明会变得更长。我可以接受这样的代码,但我认为有些人认为这是一种糟糕的编程风格。
你怎么看?是否值得写 const int& over int ?我认为它无论如何都被编译器优化了,所以也许我只是在浪费时间编码它,a?
原文由 Pijusn 发布,翻译遵循 CC BY-SA 4.0 许可协议
我注意到我通常使用常量引用作为返回值或参数。我认为原因是它的工作原理与在代码中使用非引用几乎相同。但它肯定会占用更多空间,并且函数声明会变得更长。我可以接受这样的代码,但我认为有些人认为这是一种糟糕的编程风格。
你怎么看?是否值得写 const int& over int ?我认为它无论如何都被编译器优化了,所以也许我只是在浪费时间编码它,a?
原文由 Pijusn 发布,翻译遵循 CC BY-SA 4.0 许可协议
const int &
可能仍然需要传递一个指针,这与 int
的大小非常相似。它不太可能带来任何明显更好的性能。
传递 const 引用可能需要一些注意,以检查它不会是值的意外更改(例如,您调用的某些函数也可以访问它,甚至是另一个线程)。但这通常是微不足道的,除非变量具有异常长的生命周期和非常广泛的访问范围。
原文由 Audrius Meškauskas 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
在 C++ 中,我认为使用
const T&
的反模式很常见,就像在处理参数时说T
的一种聪明方式。然而,值和引用(无论是否为 const)是两个完全不同的东西,总是盲目地使用引用而不是值可能会导致细微的错误。原因是在处理引用时,您必须考虑值不存在的两个问题: 生命周期 和 别名。
举个例子,应用这种反模式的地方是标准库本身,其中
std::vector<T>::push_back
接受参数 aconst T&
而不是一个值,这可以反击,例如代码如:这段代码是一个定时炸弹,因为
std::vector::push_back
想要一个 const 引用,但执行 push_back 可能需要重新分配,如果发生这种情况意味着在重新分配之后收到的引用将不再有效( 生命周期 问题),你进入未定义行为领域¹。从今天的逻辑角度来看,C++ 更好的是接受一个值(即
void std::vector<T>::push_back(T x)
),然后有效地将该值移动到容器内的最终位置。然后调用者最终可能会使用std::move
如果认为这很重要(但请注意,原始 C++ 中不存在移动构造的想法)。如果使用 const 引用而不是值,则 别名 问题反而会成为微妙问题的根源。例如,我被这种代码咬过:
代码乍一看似乎很安全,
P2d
是一个二维点,Rect
是一个矩形,添加/减去一个点意味着平移矩形。但是,如果要将矩形翻译回原点,则编写
myrect -= myrect.tl;
代码将不起作用,因为已定义翻译运算符接受(在这种情况下)引用同一实例的成员的引用。This means that after updating the topleft with
tl -= p;
the topleft will be(0, 0)
as it should but alsop
will become at the same time(0, 0)
因为p
只是对左上角成员的引用,所以右下角的更新将不起作用,因为它将通过(0, 0)
进行翻译,因此基本上什么都不做。请不要因为
const
这个词而误以为 const 引用就像一个值。如果您尝试 使用该引用 更改被引用的对象,该词的存在只是为了给您编译错误,但这并不意味着被引用的对象是恒定的。更具体地说,由 const ref 引用的对象可以更改(例如,由于 _别名_),甚至可以在您使用它时不存在( 生命周期 问题)。在
const T&
单词 const 表示 引用 的属性,而不是被 引用对象 的属性:这是无法使用它来更改对象的属性。可能 readonly 会是一个更好的名称,因为 const 具有 IMO 在使用引用时推动对象将保持不变的想法的心理效应。您当然可以通过使用引用而不是复制值来获得令人印象深刻的加速,尤其是对于大类。但是在使用引用时,您应该始终考虑别名和生命周期问题,因为在幕后它们只是指向其他数据的指针。然而,对于“本机”数据类型(整数、双精度、指针),引用实际上会比值慢,并且使用它们代替值没有任何好处。
此外,一个 const 引用对于优化器来说总是意味着问题,因为编译器被迫偏执,并且每次执行任何未知代码时,它都必须假设所有引用的对象现在可能具有不同的值(
const
参考对于优化器来说绝对没有任何意义;这个词只是为了帮助程序员——我个人不太确定它有这么大的帮助,但那是另一回事了)。(1)显然( https://stackoverflow.com/a/18794634/320726 )标准说这种情况是有效的,但即使有这种解释(我完全不同意),问题仍然普遍存在。
push_back
不关心对象的 身份,因此应该按值获取参数。当您将 const 引用作为值传递给函数时,您有责任确保被引用的对象在函数的整个持续时间内保持活动状态。使用v.push_back(v[0])
如果没有进行预订,这完全是错误的,如果发生这种情况,IMO(鉴于push_back
签名)是调用者的错。然而,真正的逻辑错误是push_back
界面设计(故意这样做,牺牲了效率祭坛上的逻辑正确性)。不确定是否是因为该缺陷报告,但我看到一些编译器在这种特殊情况下“修复”了问题(即push_back
检查被推送的元素是否来自向量本身)。