c++ 关键字:const ,volatile , mutable ,constexpr,... c99关键字:explicit

c++ keyword
http://www.cplusplus.com/

  • const - defines that the type is constant.
  • volatile - defines that the type is volatile.
  • mutable - applies to non-static class members of non-reference non-const type and specifies that the member does not affect the externally visible state of the class (as often used for mutexes, memo caches, lazy evaluation, and access instrumentation). mutable members of const classes are modifiable. (Note: the C++ language grammar treats mutable as a storage-class-specifier, but it does not affect storage class.)

register - automatic storage duration. Also hints to the compiler to place the object in the processor's register. (deprecated) (until C+17)
使用修饰符register声明的变量属于寄存器存储类型。该类型与自动存储类型相似,具有自动存储时期、代码块作用域和内连接。
声明为register仅仅是一个请求,因此该变量仍然可能是普通的自动变量。无论哪种情况,用register修饰的变量都无法获取地址。如果没有被初始化,它的值是未定的。

volatile -告诉编译器该被变量除了可被程序修改外,还可能被其他代理、线程修改。因此,当使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,而不使用寄存器中的缓存的值。

剖析为什么在多核多线程程序中要慎用volatile关键字?

5. volatile使用建议
总的来说,volatile关键字有两种用途:一个是ISO C/C++中用来处理“异常”内存行为(此用途只保证不让编译器做任何优化,对多核CPU是否会进行乱序优化没有任何约束力),另一种是在Java/.NET(包括Visual Studio添加的扩展)中用来实现高性能并行算法(此种用途通过使用memory barrier保证了CPU/编译器的ordering,以及通过JVM或者CLR保证了对该volatile变量读写操作的原子性)。



一句话,volatile对多线程编程是非常危险的,使用的时候千万要小心你的代码在多核上到底是不是按你所想的方式执行的,特别是对现在暂时还没有引入内存模型的C/C++程序更是如此。安全起见,大家还是用Pthreads,Java.util.concurrent,TBB等并行库提供的lock/spinlock,conditional variable, barrier, Atomic Variable之类的同步方法来干活的好,因为它们的内部实现都调用了相应的memory barrier来保证memory ordering,你只要保证你的多线程程序没有data race,那么它们就能帮你保证你的程序是正确的(是的,Pthreads库也是有它自己的内存模型的,只不过它的内存模型还些缺点,所以把多线程内存模型直接集成到C/C++中是更好的办法,也是将来的趋势,但是C++1x中将不会像Java/.NET一样给volatile关键字添加acquire和release语义,而是转而提供另一种具有同步语义的atomic variables,此为后话)。如果你想实现更高性能的lock free算法,或是使用volatile来进行同步,那么你就需要先把CPU和编程语言的memory model搞清楚,然后再时刻注意Atomicity和Ordering是否被保证了。(注意,用没有acquire/release语义的volatile变量来进行同步是错误的,但是你仍然可以在C/C++中用volatile来修饰一个不是用来做同步(例如一个event flag)而只是被不同线程读写的共享变量,只不过它的新值什么时候能被另一个线程读到是没有保证的,需要你自己做相应的处理)

Herb Sutter 在他的那篇volatile vs. volatile中对这两种用法做了很仔细的区分,我把其中两张表格链接贴过来供大家参考:

volatile的两种用途
![](http://i.cmpnet.com/ddj/images/article/2009/0901/090108sutter_f1.gif)


volatile两种用途的异同
![](http://i.cmpnet.com/ddj/images/article/2009/0901/090108sutter_t1.gif)


总结:
c++用volatile 只是来保证 不让被编译器优化,并不是原子性的。(可能顺序错误, 读脏数据。  只能用mutex来强制顺序性)
只有VS(windows 平台的多线程,用volatile, 可以保证顺序性),  linux 多线程中用volatile 不保证顺序。

......

const 的赋值


void strcpy(char* dst, const char *src, int size)//demo 函数形参的const,限定原始数据不被修改
{
   //memcpy(dst,src,size);
}

size_t strlcat(char * restrict dst, const char * restrict src, size_t maxlen) {
	const size_t srclen = strlen(src);
	const size_t dstlen = strnlen(dst, maxlen);//strnlen返回的size,不超过maxlen.  [strnlen](http://linux.die.net/man/3/strnlen)
	if (dstlen == maxlen) return maxlen + srclen;
	if (srclen < maxlen - dstlen) {
		memcpy(dst + dstlen, src, srclen + 1);
	}
	else {
		memcpy(dst + dstlen, src, maxlen - dstlen - 1);
		dst[maxlen - 1] = '\0';
	}
	return dstlen + srclen;
}

int main()
{
	//一般修改常量的值==>编译错误c3892,不能给常量赋值
	
	//const int test;
	//test = 123;//error, 常量只能是 声明的时候赋值!后面再修改值error

	const int a = 100;//ok,

	int b = 123;
	int *p = &b;

	const int *p1 = p; //*p1 为const
	//p1 = NULL;    //ok,   指针地址可以修改ok
	//*p1 = 123-1;  //error,指针p1的引用, 指向的内存(b的值)为const,无法修改

	int const *p3 = p; //*p3 为const
	//p1 = NULL;   //ok
	//*p1 = 123-1; //error

	int* const p2 = p; //p2 指针地址 为const
	//p2 = NULL;   //error, 
	//*p2 = 123-1; //ok

	const int const *p4 = p;//*p4 为const (const int 没用)
	//p4 = NULL;   //ok
	//*p4 = 123-1; //error

	const int* const p5 = p;// p5 和*p5 都为const 
	//p5 = NULL;   //error
	//*p5 = 123-1; //error
    return 0;
}

总结:
1)看const右边,如果是[const p] 取地址, 则p 取地址的值(b)为const,
2)如果 const 右边是[const p],则 p的指针地址为const
3)如果 int funcA(int a) const; const在最后面,说明这个函数中,该类的成员变量不可改变。(一般用于获取函数接口,比如getMoney() const { return this->m_myMoney};如果有人要修改 this->m_myMoney 则不被允许 )

(但是用Mutable进行改变)

const_cast 修改const属性的值

const_cast

	int i = 3;                    // i is not declared const
	const int& cref_i = i;
	const_cast<int&>(cref_i) = 4; // OK: modifies i
	std::cout << "i = " << i << '\n';

	type t; // note, if this is const type t;, then t.m1(4); is UB
	t.m1(4);
	std::cout << "type::i = " << t.i << '\n';

	const int j = 3; // j is declared const
	int* pj = const_cast<int*>(&j);
	*pj = 4;         // undefined behavior!

	void (type::*mfp)(int) const = &type::m1; // pointer to member function
        //const_cast<void(type::*)(int)>(mfp);  // compiler error: const_cast does not work on function pointers

Output:
i = 4
type::i = 4

constexpr [c++11]

constexpr - specifies that the value of a variable or function can appear in constant expressions
更加严格的constexpr

explicit specifier

Specifies constructors and conversion operators (since C++11) that don't allow implicit conversions or copy-initialization.


C语言restrict关键字的使用

C99中新增加了restrict修饰的指针:由restrict修饰的指针是最初唯一对指针所指向的对象进行存取的方法,仅当第二个指针基于第一个时,才能对对象进行存取。对对象的存取都限定于基于由restrict修饰的指针表达式中。

由restrict修饰的指针主要用于函数形参,或指向由malloc()分配的内存空间。restrict数据类型不改变程序的语义。编译器能通过作出restrict修饰的指针是存取对象的唯一方法的假设,更好地优化某些类型的例程。

[典型例子]

memcpy()在C99中,restrict可明确用于memcpy()的原型,而在C89中必须进行解释。

void *memcpy(void *restrict str1, const void *restrict str2, size_t size);

/通过使用restrict修饰str1和str2来保证它们指向不重叠的对象/

stackoverflow What does the restrict keyword mean in C++?


enable_peer_access() = delete;

函数后面加 =delete 说明改函数不能被调用(编译时期,报错!!!)

2.2 delete 关键字

C++11 中,可在想要 “禁止使用” 的特殊成员函数声明后加 “= delete”,而需要保留的加 "= default" 或者不采取操作
C++11 中,delete 关键字可用于任何函数,不仅仅局限于类成员函数

class LeafOfTree{
public:
  LeafOfTree() = default;
  ~LeafOfTree() = default;

  LeafOfTree(const LeafOfTree&) = delete;  // mark copy ctor or copy assignment operator as deleted functions
  LeafOfTree & operator=(const LeafOfTree&) = delete; 
};
posted @ 2014-11-03 12:11  scott_h  阅读(489)  评论(0编辑  收藏  举报