Преобразования между типами volatile, const, volatile const и "none" - PullRequest
0 голосов
/ 25 февраля 2020

Что стандарт C ++ (11) говорит о преобразованиях между типами volatile, const, volatile const и «none»? Я понимаю, что вполне правильно и приемлемо назначать константный тип неконстантному и энергонезависимому типу, но как насчет преобразований среди следующих типов (где 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?

Ответы [ 3 ]

1 голос
/ 25 февраля 2020
a = b; // implicit conversion from const to volatile; okay?

То, что это "хорошо", зависит от типа T.

. Здесь происходит преобразование lvalue-в-значение. Вот что говорят стандартные правила:

[conv.lval]

Glvalue нефункционального типа, не являющегося массивом T, может быть преобразовано в prvalue. Если T - неполный тип, программа, которая требует этого преобразования, плохо сформирована. Если T не тип класса, тип prvalue является cv-неквалифицированной версией T. В противном случае тип prvalue равен T.

Так, если, например, T не является типом класса, тогда значение преобразования T const b будет равно T, что в данном случае совпадает с типом назначенной переменной. Таким образом, если T присваивается (т. Е. Не является константой), то это "нормально".

Для типов классов, то, является ли присвоение "хорошо", зависит от того, какой тип оператора (ов) присваивания класс имеет. Оператор неявного присваивания не является энергозависимым, поэтому примерное присваивание будет , а не"в порядке". Это было бы плохо сформировано. Но можно сделать так, чтобы пользователь объявил изменчивый квалифицированный оператор присваивания, хотя это довольно редко.

1 голос
/ 25 февраля 2020

Что вы можете назначить на что?

Вы всегда можете присвоить изменчивые значения неконстантным значениям. Вы также можете назначить постоянные и неконстантные значения энергозависимым значениям. Вы никогда не можете ничего присвоить константным значениям, потому что они константные.

Произошло ли преобразование?

Нет - это просто выполнение задания.

Почему это так?

volatile означает, что любой доступ к объекту не может быть оптимизирован . На самом деле очень мало случаев, когда volatile когда-либо нужен или используется. Это следующие случаи:

  • Когда вы рассчитываете время операции и не хотите, чтобы вычисление было оптимизировано (используйте для этого библиотеку сравнительного анализа. Не катите свою собственную)
  • Когда вы делаете IO с отображением памяти. В этом случае вы хотите гарантировать, что чтение и запись не оптимизированы, поэтому можно использовать volatile.

Из-за этого должна быть возможность назначить volatile обычным объектам и наоборот. В то же время, однако, изменчивые ссылки не должны неявно преобразовываться в обычные ссылки, поскольку это может привести к оптимизации чтения и записи.

А как насчет const?

Вы можете назначить const вещи на что угодно, но ничто не может быть назначено на const (потому что это const).

0 голосов
/ 25 февраля 2020

Относительно fcn(a); // implicit conversion from volatile to non-volatile; okay?, это не нормально в соответствии с this , так как это приведет к ссылке на энергозависимый тип из энергонезависимого типа:

C Standard, 6.7.3 [ISO / IEC 9899: 2011], состояния

Если предпринята попытка обратиться к объекту, определенному с типом, определенным с помощью volatile, посредством использования lvalue с тип, не квалифицированный как volatile, поведение не определено.


Кроме того, хотя у меня нет ссылки, я считаю, что присваивание и преобразования между указателями должны иметь одинаковые volatile- / квалифицированный константный тип, на который они указывают (т. е. const s / volatile s до совпадения *):

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

...