鉴于以下课程:
class MyClass {
public:
int value() const {
return value_;
}
private:
volatile int value_;
};
还是必须将value()成员函数标记为volatile以避免被优化掉或者写得好吗?感谢。
答案 0 :(得分:7)
这完全类似于const
的工作方式。
如果您有const
个对象,则只有标记为const
的成员函数才可以调用。
所以......
如果您有volatile
个对象,则只有标记为volatile
的成员函数才可以调用。
只要对象本身不是volatile
,函数是否正常就没有区别。
但是,请记住,volatile
没有与多线程有关,并且不可帮助您编写线程安全的代码。对于任何与并发相关的东西,它都是错误的工具。
答案 1 :(得分:4)
是否还必须将value()成员函数标记为volatile以避免被优化掉或者写得好吗?
将成员函数标记为volatile将不会影响它是否被优化。写得很好。
担心的是我是否有MyClass c;然后调用c.value();有几次,编译器可能会认为c.value()将返回相同的值(即使它可能已经改变了..)
听起来你想要的是了解原子变量。看一下std :: atomic。
如果您真的想了解volatile,请阅读本文:http://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf
答案 2 :(得分:4)
担心的是我是否有MyClass c;然后调用c.value();有几次,编译器可能会认为c.value()将返回相同的值(即使它可能已经改变了..)
在单独的编译模型中,编译器没有看到函数的内部,它不能假设它们不会有副作用([*]),因此无法删除对函数的不同调用。如果编译器看到函数的定义并内联代码,那么看到成员是volatile
,因此也无法优化它。
[*]有些编译器(即gcc)有一些特殊的属性可以用来告诉它一个函数是 pure (即它没有副作用,输出只依赖于提供的参数)启用对要优化的函数的多个调用,例如在此循环中:
const char* lit = "Literal";
int sum = 0;
for ( int i = 0; i < strlen(lit); ++i ) {
sum += lit[i];
}
因为strlen
在库中标记为纯,所以编译器将缓存该值并将循环转换为:
const char* lit = "Literal";
int sum = 0;
int __len = strlen(lit);
for ( int i = 0; i < __len; ++i ) {
sum += lit[i];
}
但是库必须具体告诉编译器可以做到这一点。如果没有属性形式的额外信息,则不能假设任何内容,并且必须在循环的每次迭代中调用strlen
函数。
答案 3 :(得分:2)
常量和volatile成员函数(仅限C ++)
可以调用使用const限定符声明的成员函数 常量和非常量对象。非常数成员函数可以 仅为非常量对象调用。同样,一个成员函数 用volatile限定符声明可以调用volatile和 非易失性物体。只能调用非易失性成员函数 对于非易失性物体。