当从一个非易失性的int
赋值给一个volatile int
时,编译器。当从一个相同类型的非易失性的struct
赋值给一个volatile struct
时,编译器看起来非常不高兴。
考虑下面的简单程序。
struct Bar {
int a;
};
volatile int foo;
int foo2;
volatile Bar bar;
Bar bar2;
int main(){
foo = foo2;
bar = bar2;
}
当我试图编译这段代码时,我在main的第二行得到了一个错误,而不是第一行。
g++ Main.cc -o Main
Main.cc: In function ‘int main()’:
Main.cc:13:9: error: passing ‘volatile Bar’ as ‘this’ argument discards qualifiers [-fpermissive]
bar = bar2;
^
Main.cc:1:8: note: in call to ‘Bar& Bar::operator=(const Bar&)’
struct Bar {
出现这个问题似乎是因为volatile Bar
被传递到赋值运算符的左侧,尽管我不确定为什么这对int
来说不是问题。
我查看了this answer,它建议进行以下修复。
struct Bar {
int a;
volatile Bar& operator= (const Bar& other) volatile {
*this = other;
}
};
不幸的是,这导致了以下两个警告。
g++ Main.cc -o Main
Main.cc: In member function ‘volatile Bar& Bar::operator=(const Bar&) volatile’:
Main.cc:4:21: warning: implicit dereference will not access object of type ‘volatile Bar’ in statement
*this = other;
^
Main.cc: In function ‘int main()’:
Main.cc:16:15: warning: implicit dereference will not access object of type ‘volatile Bar’ in statement
bar = bar2;
然后我查看了this answer,它提到我应该 * 将引用强制转换为右值 *,但是我不确定要强制转换哪个引用,以及在这种情况下使用哪种强制转换语法。
要使main
的第2行上的赋值语句与main
的第1行上的赋值语句完全相同,并且没有警告或错误,正确的咒语是什么?
2条答案
按热度按时间jgwigjjp1#
您最初的问题是因为隐式赋值运算符具有签名
...并且对于
volatile
对象是不可调用的。警告是因为你的更新函数返回了一个volatile引用,但是这个引用从未被使用过。GCC认为这可能是个问题。解决这个问题的最简单的方法是将返回类型改为void!还有一个问题:你的函数将在无限递归中调用自己。我建议如下:
这意味着当使用volatile结构体时,你将不能链接赋值操作符。我Assert这不是一个巨大的损失。
最后旁白:为什么要使用
volatile
-它对多线程代码不是很有用(它对内存MapIO很有用)。ztigrdn82#
@martin很好地描述了问题发生的原因,但没有提供不丢弃volatile的通用解决方案。
如果可以抛弃volatile,那么应该在赋值之前在函数外部完成,而将其隐藏在复制构造函数中会留下更多不可预见的bug。
稍微调整解决方案,可得到以下更通用的解决方案:
这个版本的复制构造函数适用于volatile/non-volatile源和目标的所有4种组合,但是,如果您希望针对每种情况进行优化,也可以将其拆分为不同的组合。