C++ - 应用于方法时,挥发性代表什么?

发布于 2024-10-19 04:52:54 字数 678 浏览 6 评论 0原文

如果我有一个 C++ 方法声明,如下所示:

class A
{
public:
   double getPrice() volatile;
};
  1. 这里 volatile 代表什么?
  2. 它可以用来做什么?

您可能对 Andrei Alexandrescu 撰写的这篇 Dobbs 博士的文章感兴趣。我是:)

编辑: 那篇文章是不久前写的,现在社区似乎已经继续前进。赫伯·萨特 (Herb Sutter) 是这么说的这个。谢谢 Iain(和 Herb!)

@metal 指出 Andrei 有一篇后续文章这里,他继续提倡使用易失性正确性作为检测支持类 POSIX 互斥体的系统上的竞争条件的有价值的工具。

If I have a C++ method declaration as follows:

class A
{
public:
   double getPrice() volatile;
};
  1. What does volatile represent here?
  2. What could it be used for?

You might be interested in this Dr Dobbs article by Andrei Alexandrescu. I was :)

Edit:
That article was written a while back and now it seems that the community has moved on. Herb Sutter has this to say this. Thanks Iain (and Herb!)

@metal points out that Andrei had a follow up article here where he continues to advocate the use of volatile correctness as a valuable tool for detecting race conditions on systems supporting POSIX-like mutexes.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

放赐 2024-10-26 04:52:54

您可能熟悉 const 方法和 const 正确性(参见中的“第 15 条 - 主动使用 const”C++ 编码标准 由 Sutter 和 Alexandrescu 编写),易失性 的工作方式类似但略有不同,以产生可能的结果被称为“易失性正确性”。

const 一样,volatile 是类型修饰符。当附加到成员函数(如示例中所示)时,任一修饰符(或两者!)意味着调用该方法的对象必须具有或可转换为该类型。

考虑:

struct A
{
  void f();
  void cf() const;
  void vf() volatile;
  void cvf() const volatile;
  // ...
};

void foo( A& a, const A& ca, volatile A& va, const volatile A& cva )
{
  a.f();    // Ok
  a.cf();   // Ok: Can convert non-const    obj to const    obj
  a.vf();   // Ok: Can convert non-volatile obj to volatile obj
  a.cvf();  // Ok: Can convert non-cv       obj to cv       obj

  ca.f();   // Error: can't call non-const method on const obj
  ca.cf();  // Ok
  ca.vf();  // Error: can't call non-const method on const obj
  ca.cvf(); // Ok: Can convert

  va.f();   // Error: can't call non-volatile method on volatile obj
  va.cf();  // Error: can't call non-volatile method on volatile obj
  va.vf();  // Ok
  va.cvf(); // Ok: Can convert

  cva.f();   // Error: can't call non-cv method on cv obj
  cva.cf();  // Error: can't call non-cv method on cv obj
  cva.vf();  // Error: can't call non-cv method on cv obj
  cva.cvf(); // Ok
}

请注意,这些是编译时错误,而不是运行时错误,这就是它的潜在用处。

常量正确性可以防止编译时出现无意的错误,并使代码“更容易”理解、跟踪和推理”(Sutter 和 Alexandrescu)。易失性正确性的功能类似,但使用较少(请注意,C++ 中的 const_cast 可以丢弃 constvolatileconst volatile,但不是将其称为 cv_cast 或类似名称,而是单独以 const 命名,因为它更常用于仅丢弃 const< /代码>)。

例如,Andrei Alexandrescu 在 “易失性 - 多线程程序员的最佳朋友” 中给出了一些示例如何使用它让编译器自动检测多线程代码中的竞争条件。它也有很多关于类型修饰符如何工作的解释,但也可以在他的 中查看他的后续评论后续专栏


更新

请注意,C++11 更改了 const 的含义。 萨特如此说:“ const 现在确实意味着“只读,或安全地同时读取” - 要么是真正的物理/按位 const,要么是内部同步,以便任何实际写入都与任何同步可能并发 const 访问,因此调用者无法区分。”

在其他地方,他指出 C++11 添加了并发原语,易失性 仍然不是其中之一:“C++ 易失性变量(在 C# 和 Java 等语言中没有类似的变量)始终超出此范围以及任何其他变量的范围这是因为 C++ 易失性变量根本与线程或通信无关,并且不与这些事物交互,相反,C++ 易失性变量应该被视为进入语言之外的不同宇宙的门户。根据定义,该内存位置不遵循语言的内存模型,因为该内存位置由硬件访问(例如,由子卡写入),具有多个地址,或者是“奇怪的”并且超出了语言范围。 C++ 易失性变量通常是每个有关同步的准则的例外,因为它本质上总是“活泼的”并且无法使用普通工具(互斥体、原子等)进行同步,并且更普遍地存在于语言和编译器的所有正常范围之外,包括它们通常不能同步由编译器优化......有关更多讨论,请参阅我的文章'易失性与不稳定。”

You're probably familiar with const methods and const-correctness (cf. "Item 15 - Use const proactively" in C++ Coding Standards by Sutter and Alexandrescu), and volatile works in similar but slightly different ways to yield what might be called "volatile-correctness."

Like const, volatile is a type modifier. When attached to a member function as in your example, either modifier (or both!) mean that the object on which the method is called must have or be convertible to that type.

Consider:

struct A
{
  void f();
  void cf() const;
  void vf() volatile;
  void cvf() const volatile;
  // ...
};

void foo( A& a, const A& ca, volatile A& va, const volatile A& cva )
{
  a.f();    // Ok
  a.cf();   // Ok: Can convert non-const    obj to const    obj
  a.vf();   // Ok: Can convert non-volatile obj to volatile obj
  a.cvf();  // Ok: Can convert non-cv       obj to cv       obj

  ca.f();   // Error: can't call non-const method on const obj
  ca.cf();  // Ok
  ca.vf();  // Error: can't call non-const method on const obj
  ca.cvf(); // Ok: Can convert

  va.f();   // Error: can't call non-volatile method on volatile obj
  va.cf();  // Error: can't call non-volatile method on volatile obj
  va.vf();  // Ok
  va.cvf(); // Ok: Can convert

  cva.f();   // Error: can't call non-cv method on cv obj
  cva.cf();  // Error: can't call non-cv method on cv obj
  cva.vf();  // Error: can't call non-cv method on cv obj
  cva.cvf(); // Ok
}

Note these are compile-time errors, not run-time errors, and that is where it's potential usefulness comes in.

Const-correctness prevents unintentional errors at compile-time as well as making code "easier to understand, track, and reason about" (Sutter and Alexandrescu). Volatile-correctness can function similarly but is much less used (note that const_cast in C++ can cast away const, volatile, or const volatile, but rather than calling it cv_cast or similar, it's named after const alone because it is far more commonly used for casting away just const).

For instance, in "volatile - Multithreaded Programmer's Best Friend", Andrei Alexandrescu gives some examples of how this can be used to have the compiler automatically detect race conditions in multithreaded code. It has plenty of explanation about how type modifiers work, too, but see also his follow-up comments in his subsequent column.


Update:

Note that C++11 changes the meaning of const. Thus sayeth the Sutter: "const now really does mean 'read-only, or safe to read concurrently'—either truly physically/bitwise const, or internally synchronized so that any actual writes are synchronized with any possible concurrent const accesses so the callers can’t tell the difference."

Elsewhere, he notes that while C++11 has added concurrency primitives, volatile is still not one of them: "C++ volatile variables (which have no analog in languages like C# and Java) are always beyond the scope of this and any other article about the memory model and synchronization. That’s because C++ volatile variables aren’t about threads or communication at all and don’t interact with those things. Rather, a C++ volatile variable should be viewed as portal into a different universe beyond the language — a memory location that by definition does not obey the language’s memory model because that memory location is accessed by hardware (e.g., written to by a daughter card), have more than one address, or is otherwise 'strange' and beyond the language. So C++ volatile variables are universally an exception to every guideline about synchronization because are always inherently “racy” and unsynchronizable using the normal tools (mutexes, atomics, etc.) and more generally exist outside all normal of the language and compiler including that they generally cannot be optimized by the compiler.... For more discussion, see my article 'volatile vs. volatile.'"

我家小可爱 2024-10-26 04:52:54

它是一个易失性成员,就像只能在常量对象上调用 const 成员一样,也只能在易失性对象上调用。

有什么用呢?好吧,全局 volatile 没什么用处(它经常被误解为适用于多线程——MT——编程,但在 C++ 中情况并非如此,例如参见 http://www.drdobbs.com/high-performance-computing/212701484),而 volatile 类对象的用处就更少了。

IIRC A. Alexandrescu 提议使用对易失性对象进行的类型检查来静态地确保一些对 MT 编程有用的属性(假设在调用成员函数之前已获取锁定)。遗憾的是,我找不到那篇文章了。 (这里是:http://www.drdobbs.com/184403766

编辑:添加了来自的链接评论(它们也添加在问题中)。

It is a volatile member which, just like a const member can only be called on const objects, can only be called on volatile objects.

What's the use? Well, globally volatile is of little use (it is often misunderstood to be applicable for multi-threaded -- MT -- programming, it isn't the case in C++, see for instance http://www.drdobbs.com/high-performance-computing/212701484), and volatile class objects are even less useful.

IIRC A. Alexandrescu has proposed to use the type checking done on volatile objects to statically ensure some properties usefull for MT programming (say that a lock has been taken before calling a member function). Sadly, I don't find the article back. (Here it is: http://www.drdobbs.com/184403766)

Edit: added links from the comments (they where added also in the question).

败给现实 2024-10-26 04:52:54

在成员函数(唯一可以具有 cv 限定符的函数)中,constvolatile 有效地修改 this 指针。因此,就像 const 成员函数只能像通过 const 指针一样访问对象一样,易失性成员函数只能像通过 const 指针一样访问对象如果通过易失性指针。

易失性 的非正式含义是,对象可能会因程序外部的情况(例如内存映射 I/O 或共享内存)而发生更改。确切的含义是,对 易失性数据的任何访问都必须按照代码中编写的实际情况进行,并且不能相对于其他易失性数据进行优化或更改顺序> 访问或 I/O 操作。

这意味着任何与 易失性成员函数中的对象相关的操作都必须按照编写的顺序完成。

此外,易失性成员函数只能调用其他易失性(或const 易失性)成员函数。

至于有什么用……说实话,我现在想不出什么好的用处。易失性对于某些数据对象至关重要,例如指向 I/O 寄存器的指针,但我无法想象为什么易失性成员函数会有用。

In member functions (the only functions that can have cv-qualifiers), the const or volatile effectively modifies the this pointer. Therefore, like a const member function can access the object only as if through a const pointer, a volatile member function can access the object only as if through a volatile pointer.

The informal meaning of volatile is that an object can change due to circumstances outside the program (such as memory-mapped I/O or shared memory). The precise meaning is that any access to volatile data must be done in reality as it is written in the code, and may not be optimized out or changed in order relative to other volatile accesses or I/O operations.

What this means is that any operations relating to the object in volatile member functions must be done in order as written.

Further, a volatile member function can only call other volatile (or const volatile) member functions.

As for what use it is...frankly, I can't think of a good use right now. volatile is vital for some data objects, such as pointers pointed to I/O registers, but I can't think of why a volatile member function would be useful.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文