const_cast(this) 性能命中

const_cast(this) performance hit

据我所知,在 class 中创建常量函数对于 read/write 编译器优化很有用。

class 中的常量函数意味着 class 成员在函数执行期间将保持不变。 但是,您可以通过 const 转换隐式参数来绕过它(当然,这是一种非常糟糕的做法)。

我的问题如下:

以下代码会造成哪些陷阱(尤其是在与线程同步无关的性能方面)?

 int myClass::getSomething() const
 {
     myClass* writableThis = const_cast<myClass*>(this);
     writableThis->m_nMemberInt++;
     ...
     return m_nSomeOtherUnchangedMember;
 }

另一个相关问题:

行为compiler/platform/os具体吗?

如果有人能解释这种代码是 compiled/executed 的幕后魔法,我也将不胜感激(我推测 CPU 正在进行乱序优化基于函数是 const 的事实,在实际执行期间不遵守这一点应该会产生一些副作用)。

编辑:

感谢您为我澄清这一点。经过进一步研究,收到的所有答案都是正确的,但我只能接受一个:)。

关于仅用于语法正确性的 const 限定符,我相信这个答案既是对又是错误的,正确的表述方式(恕我直言)是它主要用于语法正确性(在非常有限的范围内)它可以产生不同/更好的代码的场景数量)。参考资料:SO Related question , related article

CPU 对 const 一无所知,这是一个 C++ 关键字。当编译器将 C++ 代码转换为汇编代码时,所剩无几。

当然,由于 const 关键字,生成的代码确实有可能 完全 不同。例如,某些 operator[]const 版本可能 return 一个 T 对象的值,而非常量版本必须 return 一个 T& .一个CPU连自己在什么函数都不知道,甚至假设函数的存在

const_cast<T>(this) 技巧可能不安全,因为您的成员函数的用户可能 运行 进入未定义的行为,而他们并没有做错任何事。

问题是只有当您从非常量对象开始时才允许放弃常量性。如果您的对象是常量,则放弃其常量并使用结果指针更改对象状态的函数会触发未定义的行为:

struct Test {
    int n;
    Test() : n(0) {}
    void potentiallyUndefinedBehavior() const {
        Test *wrong = const_cast<Test*>(this);
        wrong->n++;
    }
};

int main() {
    Test t1;
    // This call is OK, because t1 is non-const
    t1.potentiallyUndefinedBehavior();
    const Test t2;
    // This triggers undefined behavior, because t2 is const
    t2.potentiallyUndefinedBehavior();
    return 0;
}

发明了 const_cast<T>(this) 的技巧,用于在带有 const 限定符的成员函数中缓存值。然而,它不再有用,因为 C++ 为这类事情添加了一个特殊的关键字:通过标记一个成员 mutable 你可以使该成员在 const 限定的方法中可写:

struct Test {
    mutable int n;
    Test() : n(0) {}
    void wellDefinedBehavior() const {
        n++;
    }
};

现在 const 成员函数将不会触发未定义的行为,无论上下文如何。

我的答案是使用存储 class mutable 来存储任何需要在 const 方法中修改的东西。

它内置于语言中,因此有几个好处。它更严格地控​​制 const 方法如何修改数据成员。其他开发人员会知道这些数据成员会在 const 方法中发生变化。如果有任何编译器优化,编译器就会知道做正确的事情。

class myClass {
private:
    int m_nSomeOtherUnchangedMember;
    mutable int m_nMemberInt;
    …

public:
    int getSomething() const;
    …
};

int myClass::getSomething() const
{
    m_nMemberInt++;
    …
    return m_nSomeOtherUnchangedMember;
}

As far as I know , making constant functions in a class is useful for read/write compiler optimizations.

没有。我们使用 const 方法来强制执行语义保证,不允许优化(避免复制可能是例外)。

What pitfalls can the following code cause

  1. 首先,它可以破坏程序语义。

    例如,std::map 个节点存储 std::pair<const Key, T>,因为 Key 在插入后不应发生变化。如果键更改值,则映射排序不变量不正确,后续 find/insert/rebalance 操作将出现异常。

    如果您在这个 const 键上调用一个 const 限定的方法,并且该方法以影响其比较方式的方式更改 Key,那么您就狡猾地破坏了地图。

  2. 其次,它会杀死你的程序。如果你有一个 const 对象覆盖在一个真正只读的地址范围上,或者你有一个静态初始化的 const 对象在只读初始化数据段,那么写入它会导致某种保护错误

正如其他人所说,const 正确性旨在为程序员提供帮助,而不是为优化器提供帮助。你应该记住 4 件事:

1。 const 引用和 const 方法并不快

2。 const 引用和 const 方法并不快

3。 const 引用和 const 方法并不快

4。 const 引用和 const 方法并不快

更具体地说,优化器完全忽略了引用或方法的常量性,因为 const 在那种情况下并不真正意味着你在想什么。

对对象的 const 引用并不意味着例如在执行方法期间对象将保持不变。考虑例如:

struct MyObject {
    int x;
    void foo() const {
        printf("%i\n", x);
        char *p = new char[10];
        printf("%i\n", x);
        delete[] p;
    }
};

编译器不能假定 x 成员在对 printf 的两次调用之间没有发生变化。原因是 std::operator new 全局分配器可能已经过载并且代码可能具有指向实例的常规非常量指针。因此,全局分配器在 foo 执行期间更改 x 是完全合法的。编译器不知道这不会发生(全局分配器可能在另一个 编译单元)。

调用任何未知代码(即基本上任何非内联函数)都可以改变对象的任何部分,无论是否在 const 方法中。 const 方法只是表示不能使用 this 来改变对象,并不是说对象是常量。

如果 const 正确性真的对程序员有帮助是另一个问题,我个人对此持异端观点,但那是另一回事了...