gpt4 book ai didi

C++ 常量引用语义?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:03:12 27 4
gpt4 key购买 nike

考虑下面的示例应用程序。它展示了我所说的有缺陷的类设计。

#include <iostream>

using namespace std;

struct B
{
B() : m_value(1) {}

long m_value;
};

struct A
{
const B& GetB() const { return m_B; }

void Foo(const B &b)
{
// assert(this != &b);
m_B.m_value += b.m_value;
m_B.m_value += b.m_value;
}

protected:
B m_B;
};

int main(int argc, char* argv[])
{
A a;

cout << "Original value: " << a.GetB().m_value << endl;

cout << "Expected value: 3" << endl;
a.Foo(a.GetB());

cout << "Actual value: " << a.GetB().m_value << endl;

return 0;
}

输出:
原始值:1
期望值:3
实际值:4

很明显,程序员被 b 的常量所愚弄。 b 错误地指向了 this,这会产生不良行为。

我的问题:在设计 getter/setter 时应该遵循哪些构造规则?

我的建议:如果可以通过成员函数通过引用设置成员变量,则永远不要返回对成员变量的引用。因此,要么按值返回,要么按值传递参数。 (无论如何,现代编译器都会优化掉额外的拷贝。)

最佳答案

Obviously, the programmer is fooled by the constness of b

正如有人曾经说过的,您一直在使用这个词。我不认为这意味着你认为的意思。

Const 表示您不能更改该值。这并不意味着该值不能更改。

如果程序员被其他一些代码可以改变他们不能改变的东西这一事实所愚弄,他们需要在别名方面有更好的基础。

如果程序员被标记“const”听起来有点像“常量”但意思是“只读”这一事实所愚弄,他们需要更好地了解他们正在使用的编程语言的语义。

因此,如果您有一个返回 const 引用的 getter,那么它就是您无权更改的对象的别名。这说明没有它的值是否是不可变的。


最终,这归结为缺乏封装,并且没有应用 Demeter 法则。通常,不要改变其他对象的状态。向他们发送一条消息,要求他们执行一项操作,这可能(取决于他们自己的实现细节)改变他们的状态。

如果您将 B.m_value 设为私有(private),那么您将无法编写您拥有的 Foo。你要么将 Foo 变成:

void Foo(const B &b)
{
m_B.increment_by(b);
m_B.increment_by(b);
}

void B::increment_by (const B& b)
{
// assert ( this != &b ) if you like
m_value += b.m_value;
}

或者,如果你想确保这个值是常量,使用一个临时的

void Foo(B b)
{
m_B.increment_by(b);
m_B.increment_by(b);
}

现在,增加一个值本身可能合理也可能不合理,并且很容易在 B::increment_by 中进行测试。您还可以测试 A::Foo 中是否有 &m_b==&b,尽管一旦您有几个级别的对象和引用其他对象而不是值的对象(所以 &a1.b.c == &a2.b.c 并不意味着 &a1.b==&a2.b&a1==&a2 ),那么你真的只需要知道任何操作都可能是别名。

别名意味着按表达式递增两次与第一次计算表达式的值递增不同;没有真正的解决方法,在大多数系统中,复制数据的成本不值得冒避免别名的风险。

传递结构最少的参数也很有效。如果 Foo() 花费了 long 而不是它必须从中获取 long 的对象,那么它就不会遭受别名,并且您不需要编写不同的 Foo() 来将 m_b 递增 C 的值。

关于C++ 常量引用语义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3022220/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com