volatile、const、volatile const 和 "neither" 类型之间的转换

Conversions between volatile, const, volatile const, and "neither" types

C++(11) 标准对 volatile、const、volatile const 和 "neither" 类型之间的转换有何规定?我知道将 const 类型分配给非 const 和非 volatile 类型是定义明确且可以接受的,但是在以下类型(其中 T 是某种类型)之间进行转换呢?

// T
T
T volatile
T const 
T volatile const 

// Pointer-to-T
T*
T volatile*
T const*
T volatile const*

// Volatile pointer-to-T
T* volatile
T volatile* volatile
T const* volatile
T volatile const* volatile

// Const pointer-to-T
T* const
T volatile* const
T const* const
T volatile const* const

// Volatile const pointer-to-T
T* volatile const
T volatile* volatile const
T const* volatile const
T volatile const* volatile const

作为一个简单的例子,请考虑以下代码:

T volatile a;
T const b;

a = b; // implicit conversion from const to volatile; okay?

template<typename T>
void fcn(T& t)
{
    t = b; // implicit conversion from const to non-const, which I assume is okay
}
fcn(a); // implicit conversion from volatile to non-volatile; okay?

你能分配给什么?

您始终可以将 volatile 值分配给非常量值。您还可以将 const 和非常量值分配给 volatile 值。您永远不能将任何内容分配给 const 值,因为它们是 const。

是否发生转换?

不 - 它只是在做作业。

这是为什么?

volatile 意味着对对象的任何访问 都无法优化掉 。实际上很少有需要或使用 volatile 的情况。这些案例是:

  • 当您对操作进行计时,并且不希望优化计算时(请为此使用基准库。不要自己动手)
  • 当你在做内存映射IO的时候。在这种情况下,您希望保证读取和写入不会被优化掉,因此可以使用 volatile。

因此,必须可以将 volatile 分配给常规对象,反之亦然。然而,与此同时,volatile 引用 不应该 隐式转换为常规引用,因为这可能会导致读取和写入被优化。

const呢?

您可以将 const 东西分配给任何东西,但不能将任何东西分配给 const(因为它是 const)。

a = b; // implicit conversion from const to volatile; okay?

是否"okay"取决于类型T

这里发生的是左值到右值的转换。标准规则是这样说的:

[conv.lval]

A glvalue of a non-function, non-array type T can be converted to a prvalue. If T is an incomplete type, a program that necessitates this conversion is ill-formed. If T is a non-class type, the type of the prvalue is the cv-unqualified version of T. Otherwise, the type of the prvalue is T.

因此,如果例如 T 不是 class 类型,那么从 T const b 转换的纯右值将是 T,这是相同的在这种情况下作为分配变量的类型。所以,只要 T 是可赋值的(即不是 const),它就是 "okay".

对于class类型,赋值是否为"okay",取决于class有什么样的赋值运算符。隐式赋值运算符不是 volatile 限定的,因此示例赋值将 而不是 是 "okay"。它的格式不正确。但是可以让用户声明一个 volatile 限定赋值运算符,尽管这种情况很少见。

关于 fcn(a); // implicit conversion from volatile to non-volatile; okay?,根据 this,这是不正确的,因为它会导致从非易失性类型引用易失性类型:

The C Standard, 6.7.3 [ISO/IEC 9899:2011], states

If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.


此外,虽然我没有引用,但我相信指针之间的赋值和转换必须具有相同的 volatile-/const- 它们指向的合格类型(即 consts/ * 之前的 volatiles 必须匹配):

T volatile* volatile t; T volatile* volatile const t1 = t; // okay; initializing const with non-const T* volatile t2 = t; // not okay; t and t2 point to different types T volatile const* volatile t3 = t; // not okay; t and t3 point to different types