C ++中“const”的用法有多less?

作为一名新手C ++程序员,有一些对我来说看起来还是很模糊的构造,其中一个是const 。 你可以在很多地方使用它,并有许多不同的效果,初学者几乎不可能活着出来。 一些C ++大师会一次解释一下各种用法和/或为什么不使用它们?

试图收集一些用途:

绑定一些临时引用到常量,以延长其生命。 引用可以是一个基础 – 而且它的析构函数不需要是虚拟的 – 正确的析构函数仍然被调用:

 ScopeGuard const& guard = MakeGuard(&cleanUpFunction); 

说明 ,使用代码:

 struct ScopeGuard { ~ScopeGuard() { } // not virtual }; template<typename T> struct Derived : ScopeGuard { T t; Derived(T t):t(t) { } ~Derived() { t(); // call function } }; template<typename T> Derived<T> MakeGuard(T t) { return Derived<T>(t); } 

这个技巧在Alexandrescu的ScopeGuard实用程序类中使用。 一旦临时超出范围,Derived的析构函数被正确调用。 上面的代码忽略了一些小的细节,但是这是很重要的。


用const来告诉别人方法不会改变这个对象的逻辑状态。

 struct SmartPtr { int getCopies() const { return mCopiesMade; } }; 

对于写时复制类使用const ,以使编译器帮助您决定何时何时不需要复制。

 struct MyString { char * getData() { /* copy: caller might write */ return mData; } char const* getData() const { return mData; } }; 

说明 :只要原始数据和复制对象的数据保持不变,您可能希望在复制某些内容时共享数据。 一旦对象之一改变了数据,你现在需要两个版本:一个是原始的,一个是复制的。 也就是说,你复制一个对象的写入 ,所以他们现在都有自己的版本。

使用代码

 int main() { string const a = "1234"; string const b = a; // outputs the same address for COW strings cout << (void*)&a[0] << ", " << (void*)&b[0]; } 

上面的代码片段在我的GCC上打印相同的地址,因为使用的C ++库实现了copy-on-write std::string 。 两个string,即使它们是不同的对象,也为它们的string数据共享相同的内存。 使b非const将更喜欢operator[]的非const版本,GCC将创build后备内存缓冲区的副本,因为我们可以更改它,并且不会影响!

 int main() { string const a = "1234"; string b = a; // outputs different addresses! cout << (void*)&a[0] << ", " << (void*)&b[0]; } 

复制构造函数从const对象和临时对象复制

 struct MyClass { MyClass(MyClass const& that) { /* make copy of that */ } }; 

为了使常数,平凡不能改变

 double const PI = 3.1415; 

通过引用而不是按值传递任意对象 – 以防止可能的昂贵或不可能的值传递

 void PrintIt(Object const& obj) { // ... } 

C ++中的const有两个主要用途。

Const值

如果一个值的forms是一个variables,成员或参数,它不会(或不应该)在其生命期内被改变,你应该把它标记为const。 这有助于防止对象上的突变。 例如,在下面的函数中,我不需要改变传入的Student实例,所以我把它标记为const。

 void PrintStudent(const Student& student) { cout << student.GetName(); } 

至于你为什么要这样做。 如果知道底层数据不能改变,那么推理algorithm就容易多了。 “const”有帮助,但不能保证这将实现。

显然,打印数据到cout不需要太多的思考:)

将成员方法标记为const

在前面的例子中,我将Student标记为const。 但是,C ++是如何知道在学生上调用GetName()方法不会改变对象呢? 答案是这个方法被标记为const。

 class Student { public: string GetName() const { ... } }; 

标记一个方法“const”做两件事。 主要是告诉C ++这个方法不会改变我的对象。 第二件事就是现在所有的成员variables都被当作是const标记的。 这有助于但不妨碍你修改你的类的实例。

这是一个非常简单的例子,但希望这将有助于回答你的问题。

注意了解这4个声明之间的区别:

以下两个声明在语义上是相同的。 您可以更改ccp1和ccp2指向的位置,但不能更改它们指向的内容。

 const char* ccp1; char const* ccp2; 

接下来,指针是const的,所以为了有意义,它必须被初始化为指向某个东西。 你不能把它指向别的东西,但它指向的东西可以改变。

 char* const cpc = &something_possibly_not_const; 

最后,我们把两者结合起来,所以指向的东西不能被修改,指针也不能指向其他任何地方。

 const char* const ccpc = &const_obj; 

顺时针螺旋规则可以帮助解开一个声明http://c-faq.com/decl/spiral.anderson.html

正如我在这里读到的,注意到这一点很有用

const适用于它的左边的任何东西(除了在这种情况下它不适用于它的直接权利)。