【问题标题】:C++: const volatile methodsC++:常量易失方法
【发布时间】:2012-01-25 16:58:48
【问题描述】:

我的脑抽筋了:

struct MyStruct
{
    int x;

    ...

    inline int getX1() const { return x; }
    inline int getX2() const volatile { return x; }
};

volatile MyStruct myStruct;

我了解编译器将允许我调用 myStruct.getX2() 而不允许我调用 myStruct.getX1(),因为在 volatile 结构/类上调用的方法必须在这些方法上具有 volatile 限定符。

这是我的问题:如果我创建了这样一个类,并发布它以供其他软件例程使用,我会在方法上添加或不添加 volatile 限定符的原因是什么?

是不是因为一个标记为volatile 的方法告诉编译器不要假设它的任何成员不是volatile,为了优化目的,而如果一个方法没有标记volatile,那么任何成员都没有标记@987654328 @可以优化吗?

【问题讨论】:

标签: c++ volatile qualifiers


【解决方案1】:

该标准没有为任何标准类提供volatile 成员函数,因此在正常情况下您也不应该提供。

您在最后一段中的含义是正确的——就像const 成员函数一样,在volatile 成员函数中this 是一个指向易失性的指针。因此,无论您的实现如何实现易失性内存访问(禁用各种优化,对于初学者),它都会通过this 进行任何访问。

我怀疑只值得为一个包装了一些内存的类提供volatile 成员函数,而这些内存可能实际上是易失的或可能不是。然后用户可以根据需要创建volatile 或非volatile 对象。如果内存肯定需要是易失性的,那么我认为你最好使用具有volatile 数据成员的非volatile 对象。

现在我正在尝试想象一个真正的用途——一个“计数器”类,它可以在由硬件或您编写的中断更新的幻地址之上创建(在这种情况下,您可以创建一个带有新位置的 volatile 实例),但也有一个用例,它只通过“正常”代码的调用来更新(在这种情况下,它可以是一个非易失性实例)。在这两种情况下,您可能只会承受使数据成员易失的“性能损失”,因为它没有其他危害。但是您可以提供成员函数的volatile 和非volatile 版本,包含相同的代码,其中一个将被优化,另一个则不会。

【讨论】:

  • std::atomic 的大多数成员函数都有volatile 重载。
  • “那么我认为你最好使用具有易失性数据成员的非易失性对象” - 确切地说 - 我实际上有一个顶级对象,它具有具有数据成员的易失性成员对象。 (有一个原因,我不能在这里进入。)
  • @Steve 我最终从 Google 来到这里,因为放置 new 不适用于 volatile 指针。见:ideone.com/FHTVr
  • @Eloff:是的。您使用placement new 创建易失性对象的“正常”方式是:ideone.com/LlTqm。在我的回答中,如果您在易失性内存的顶部创建特殊对象,我认为只要您的构造函数不读取或修改内存,就可以将指针常量转换为非易失性(如果构造函数是微不足道的,这将得到满足)。为了安全起见,也许您应该为该类重载placement new,提供volatile void* 版本,并在其中做一些与实现相关的事情,而不是调用常规的placement new。
【解决方案2】:

是否因为标记为 volatile 的方法告诉编译器不要假设其任何成员都不是 volatile 以进行优化,而如果方法未标记为 volatile,则任何未标记为 volatile 的成员都可以优化?

是的。

volatile 函数中,*this 对象变为volatile,这反过来意味着类的每个非静态成员都变为volatile,就像在const 函数中一样,*this 对象变为const,这反过来意味着该类的每个非静态成员都变为const

话虽如此,编译不会积极优化涉及volatile 函数中成员的代码。

【讨论】:

    猜你喜欢
    • 2015-02-26
    • 2015-10-06
    • 2012-05-26
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多