繁体   English   中英

const_cast(this)性能命中

[英]const_cast(this) performance hit

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

类中的常量函数意味着类成员在函数执行期间将保持不变。 但是,您可以通过const强制转换隐式参数来绕过此操作(ofc,这是非常糟糕的做法)。

我的问题如下:

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

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

另一个相关的问题:

行为编译器/平台/操作系统是否特定?

如果有人在编译/执行这样的代码时能在幕后解释魔术,我也将不胜感激(我推测CPU根据函数const的事实进行了无序的优化,并且在实际执行过程中不遵守此规定会产生一些副作用)。

编辑:

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

关于仅用于语法核心的const限定词,我相信这个答案是对还是错,正确的表达方式(imho)将是它主要用于语法核心(在非常有限的情况下,它可以产生不同/更好的代码)。 参考文献: SO相关问题相关文章

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成员函数都不会触发未定义的行为。

CPU不了解const ,这是C ++关键字。 到编译器将C ++代码转换为汇编代码时,剩下的还不多。

当然,由于const关键字,很有可能生成的代码完全不同。 例如,某些operator[]const版本可以按值返回T对象,而非const版本必须返回T& CPU甚至不知道它所处的功能,甚至不知道功能的存在。

我的答案是对需要在const方法中修改的任何事物使用mutable的存储类。

它内置在语言中,因此有很多好处。 对于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;
}

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

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

以下代码可能导致什么陷阱

  1. 首先,它会破坏程序的语义。

    例如, std::map节点存储std::pair<const Key, T> ,因为在插入Key后不应对其进行突变。 如果键更改了值,则表示地图排序不变式不正确,并且随后的查找/插入/重新平衡操作将不正常。

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

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

正如其他陈述所指出的那样,const正确性旨在为程序员提供帮助,而不是为优化器提供帮助。 您应该记住4件事:

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

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

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

4. const引用和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正确性确实对程序员有帮助,那么我个人就有一个非常异端的观点,这是另一个故事...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM