C++ 中“const”的用途有多少?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/455518/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How many and which are the uses of "const" in C++?
提问by tunnuz
As a novice C++ programmer there are some constructs that look still very obscure to me, one of these is const
. You can use it in so many places and with so many different effects that is nearly impossible for a beginner to come out alive. Will some C++ guru explain once forever the various uses and whether and/or why not to use them?
作为一名 C++ 新手程序员,有一些结构对我来说看起来仍然很模糊,其中之一是const
. 您可以在如此多的地方使用它并产生如此多的不同效果,这对于初学者来说几乎是不可能的。某些 C++ 大师会永远解释一下各种用途以及是否和/或为什么不使用它们?
采纳答案by Johannes Schaub - litb
Trying to collect some uses:
尝试收集一些用途:
Binding some temporary to reference-to-const, to lengthen its lifetime.The reference can be a base - and the destructor of it doesn't need to be virtual - the right destructor is still called:
将一些临时绑定到const 引用,以延长其生命周期。引用可以是基类 - 它的析构函数不需要是虚拟的 - 仍然调用正确的析构函数:
ScopeGuard const& guard = MakeGuard(&cleanUpFunction);
Explanation, using code:
说明,使用代码:
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); }
This trick is used in Alexandrescu's ScopeGuard utility class. Once the temporary goes out of scope, the destructor of Derived is called correctly. The above code misses some small details, but that's the big deal with it.
这个技巧用于 Alexandrescu 的 ScopeGuard 实用程序类。一旦临时超出范围,就会正确调用 Derived 的析构函数。上面的代码遗漏了一些小细节,但这就是大问题。
Use const to tell others methods won't change the logical state of this object.
使用 const 告诉其他方法不会改变这个对象的逻辑状态。
struct SmartPtr {
int getCopies() const { return mCopiesMade; }
};
Use const for copy-on-write classes, to make the compiler help you to decide when and when not you need to copy.
将 const 用于写时复制类,让编译器帮助您决定何时以及何时不需要复制。
struct MyString {
char * getData() { /* copy: caller might write */ return mData; }
char const* getData() const { return mData; }
};
Explanation: You might want to share data when you copy something as long as the data of the originally and the copie'd object remain the same. Once one of the object changes data, you however need now two versions: One for the original, and one for the copy. That is, you copyon a writeto either object, so that they now both have their own version.
说明:只要原始对象和复制对象的数据保持不变,您可能希望在复制某些内容时共享数据。一旦其中一个对象更改了数据,您现在需要两个版本:一个用于原始版本,另一个用于副本。也就是说,您在写入时复制到任一对象,以便它们现在都有自己的版本。
Using code:
使用代码:
int main() {
string const a = "1234";
string const b = a;
// outputs the same address for COW strings
cout << (void*)&a[0] << ", " << (void*)&b[0];
}
The above snippet prints the same address on my GCC, because the used C++ library implements a copy-on-write std::string
. Both strings, even though they are distinct objects, share the same memory for their string data. Making b
non-const will prefer the non-const version of the operator[]
and GCC will create a copy of the backing memory buffer, because we could change it and it must not affect the data of a
!
上面的代码片段在我的 GCC 上打印了相同的地址,因为使用的 C++ 库实现了 copy-on-write std::string
。两个字符串,即使它们是不同的对象,它们的字符串数据共享相同的内存。制作b
非常量将更喜欢非常量版本的operator[]
并且 GCC 将创建后备内存缓冲区的副本,因为我们可以更改它并且它不能影响a
!
int main() {
string const a = "1234";
string b = a;
// outputs different addresses!
cout << (void*)&a[0] << ", " << (void*)&b[0];
}
For the copy-constructor to make copies from const objects and temporaries:
对于复制构造函数从 const 对象和临时对象进行复制:
struct MyClass {
MyClass(MyClass const& that) { /* make copy of that */ }
};
For making constants that trivially can't change
用于制作无法更改的常量
double const PI = 3.1415;
For passing arbitrary objects by reference instead of by value- to prevent possibly expensive or impossible by-value passing
用于通过引用而不是按值传递任意对象- 防止可能昂贵或不可能的按值传递
void PrintIt(Object const& obj) {
// ...
}
回答by JaredPar
There are really 2 main uses of const in C++.
在 C++ 中,const 有两种主要用途。
Const values
常量值
If a value is in the form of a variable, member, or parameter that will not (or should not) be altered during its lifetime you should mark it const. This helps prevent mutations on the object. For instance, in the following function I do not need to change the Student instance passed so I mark it const.
如果值是在其生命周期内不会(或不应该)更改的变量、成员或参数的形式,则应将其标记为 const。这有助于防止对象发生突变。例如,在以下函数中,我不需要更改传递的 Student 实例,因此将其标记为 const。
void PrintStudent(const Student& student) {
cout << student.GetName();
}
As to why you would do this. It's much easier to reason about an algorithm if you know that the underlying data cannot change. "const" helps, but does not guarantee this will be achieved.
至于你为什么要这样做。如果您知道底层数据无法更改,那么推理算法就会容易得多。“const”有帮助,但不保证会实现。
Obviously, printing data to cout does not require much thought :)
显然,将数据打印到 cout 不需要太多思考:)
Marking a member method as const
将成员方法标记为 const
In the previous example I marked Student as const. But how did C++ know that calling the GetName() method on student would not mutate the object? The answer is that the method was marked as const.
在前面的示例中,我将 Student 标记为 const。但是 C++ 怎么知道在 student 上调用 GetName() 方法不会改变对象呢?答案是该方法被标记为const。
class Student {
public:
string GetName() const { ... }
};
Marking a method "const" does 2 things. Primarily it tells C++ that this method will not mutate my object. The second thing is that all member variables will now be treated as if they were marked as const. This helps but does not prevent you from modifying the instance of your class.
将方法标记为“const”有两件事。主要是它告诉 C++ 这个方法不会改变我的对象。第二件事是所有成员变量现在都将被视为它们被标记为 const。这有助于但不会阻止您修改类的实例。
This is an extremely simple example but hopefully it will help answer your questions.
这是一个非常简单的例子,但希望它能帮助回答你的问题。
回答by Steve Folly
Take care to understand the difference between these 4 declarations:
请注意理解这 4 个声明之间的区别:
The following 2 declarations are identical semantically. You can change whereccp1 and ccp2 point, but you can't change the thing they're pointing at.
以下 2 个声明在语义上是相同的。您可以更改其中CCP1和CCP2点,但你不能改变他们指向的东西。
const char* ccp1;
char const* ccp2;
Next, the pointer is const, so to be meaningful it must be initialised to point to something. You can't make it point to something else, however the thing it points to canbe changed.
接下来,指针是 const,所以为了有意义,它必须被初始化为指向某个东西。你不能让它指向别的东西,但是东西它指向可以被改变。
char* const cpc = &something_possibly_not_const;
Finally, we combine the two - so the thing being pointed at cannot be modified, and the pointer cannot point to anywhere else.
最后,我们将两者结合起来——所以被指向的东西不能被修改,指针也不能指向其他任何地方。
const char* const ccpc = &const_obj;
The clockwise spiral rule can help untangle a declaration http://c-faq.com/decl/spiral.anderson.html
顺时针螺旋规则可以帮助解开声明http://c-faq.com/decl/spiral.anderson.html