2010-10-14 69 views
5

const正确性让我有些困惑。在C++中使用const的正确方法是什么?

你用什么经验法则来决定何时应该是const或不是?

例如考虑这个例子

class MyClass 
{ 
    string ToString(); // this one? 
    const string& ToString(); // or this? 
    const string& ToString() const; // or this? 

    char* ToString(); // What about this? 
    const char* ToString(); // or this? 
    const char* ToString() const; // or this? 
    const char const* ToString(); // Is this legal? 
    const char const* ToString() const; // how about this? 
    char const* ToString(); // or even this? 
}; 

Const会变得非常混乱。

所有这些ToString方法之间有什么区别?

如果我理解正确,第一个返回一个新的字符串对象,如果需要可以修改 。 第二个返回一个常量引用,也许它应该是字符串const & ToString()。 第三个可能是废话,因为引用总是不变的是正确的?

以为我会抛出旧char *版本在那里比较,因为我有方法返回对象指针,我不知道它们是否应该是const或不。

我想我只是想了解const的正确性的限制和好处,以及如何确定某些东西是否应该是const,以及如何正确应用const,因为将const放在不同的地方会改变含义。

编辑:另外,我该如何处理'...丢弃限定符'。这实际上意味着什么?

+0

第二个和第三个之间没有什么区别。 – dan04 2010-10-14 23:51:31

+9

我宁愿从一般规则开始,“如果你可以把const放在某个地方,那么你应该。”很显然,这个规则有很多例外(其中很多),但实际上,你可以使const变量越多,推断,调试和维护代码就越容易。我认为这比起更常见的“让我们只在必要的地方使用常量,并且可能在其他地方使用常常更好”。 – 2010-10-14 23:51:42

+0

您是否阅读过Herb Sutter的GOTW文章[“Const Correctness?”](http://www.gotw.ca/gotw/006.htm)它通过一个示例类来解释(1)应该是什么'const' (2)使用'const'的效果是什么。这绝对是一个很好的起点。 – 2010-10-15 00:02:50

回答

2

您使用const的位置取决于功能的用途。正如詹姆斯暗示在他的评论(这是值得投入作为一个答案),把const任何地方,你可以:

如果该功能是为了它的对象实例上修改状态,const在年底签名。

如果该功能旨在修改其参考或指针参数中的一个,请勿将放在参数const上。

如果引用的变量通过指针或引用应该被修改,const上的类型(记住,const适用于定义之前立即的一部分)。

如果返回的引用/指针引用的变量不应该被接收到,const上的类型。

如果不知道目的的功能,回答问题中给出的例子是不可能的。我倾向于使用string ToString() constchar* ToString() const,并且有关谁负责char*的文档非常明确。


作为一个额外的笔记,const char*char const*是相同的(指针不可修改的字符)。另一方面,char* const是不可修改的指向可修改字符的指针。

+0

你的wtf/min的贡献是排序后[这里](http://area51.stackexchange.com/proposals/11464/code-review?referrer=aWNm_PdciyFqjFW8CUacGw2“代码审查”):) – greatwolf 2011-01-16 23:17:46

-1

我发现this是一个有益的指导,

+2

-1链接到C++ FQA Lite。 – 2010-10-14 23:53:19

-1

你用什么凭经验来决定何时东西应该是const或不?

在任何地方都可以使用它。然后,不要当你需要修改对象或授予访问某些可能修改对象的内容(即将引用或代理返回到内部状态)时使用它。

第三个可能是废话,因为引用总是不变的是正确的?

不,这是不正确的。引用是别名,而不是变量。因此,您无法更改引用“指向”哪个变量,就像您可以使用指针一样。但是,您可能需要引用可变对象(std::string&)。

所有这些ToString方法有什么区别?

他们都非常的内存管理技术有所不同,但在一个高的水平,他们都做同样的事情,除了以下:

char* ToString(); 

该ONT返回一个指向可变字符数组(可能是内部状态)。

注意的家人:

char const* ToString(); 
const char* ToString(); // or this? 
const char const* ToString(); // Is this legal? 

都写同样的事情不同的方式。无论您是否写入,本机类型都是按值返回时的常量。

以下2在C++返回一个字符串的首选方式(末尾提供了一个额外的const):

string ToString(); // this one? 
const string& ToString(); // or this? 

这两个您将使用的一个取决于你在哪里得到的值。如果字符串是一个数据成员,我建议你去后者,因为它通常比较快,但是如果你的字符串实现使用了写时复制语义,那么不会太多。如果您必须计算一个值并将其返回,则必须使用前者,因为您无法返回对局部变量的引用。

下面两个是正确的,但我还是建议你使用std::string

const char* ToString() const; // or this? 
const char const* ToString() const; // how about this? 
+0

'const char *'和'char const *'是可修改的p ointers不可修改的字符。 'char * const'是一个不可修改的指向可修改字符的指针。 'const'适用于它之前发生的任何事情,或者,如果它是第一个,它会立即发生。 – Zooba 2010-10-15 00:07:02

+0

括号后面的'const'不是多余的:它适用于“* this”对象,而不是返回类型。 – aschepler 2010-10-15 00:07:28

+0

糟糕,在那个上有点太快了。我会编辑它。 – 2010-10-15 00:25:37

0

您不能重载具有相同名称和相同参数但返回类型不同的函数。你可能知道,但只是确定。

const括号后的()表示该函数不会更改您调用的对象。通常称为ToString的东西不会更改对象,所以在所有情况下,您可能都需要一个const方法。

返回string和返回const string&之间的区别是,参考不作和对象复制并可能会更快,但你只能做它,如果你已经有了一个string对象(例如,作为一个私有成员MyClass)。如果没有(例如你需要将几位数据拼接在一起,然后返回该字符串),则需要按值返回string

使用string对象通常优选使用C风格char*三分球,但既然你问:第四个,char*,就会让其他代码改变返回的字符串,这可能是一件坏事内的字符。 const char*char const*const char const*都是一样的东西。 char *const在技术上是不同的,但它不会做太多的返回类型,因为返回const int并不重要的原因:调用者可以复制然后更改返回值。

总之,最好的形式是,为了:

const string& ToString() const; 
string ToString() const; 
const char* ToString() const; 
0

在这个问题的一些变化是在返回stringchar *。我认为这与const讨论无关(如果不是,请告诉我);我正在考虑string回报变化。

class MyClass 
{ 
    string ToString();    // A 
    string & ToString();   // B (I added this) 
    const string& ToString();  // C 
    const string& ToString() const; // D 
}; 

我的偏好顺序如下:

  • 返回类型说明符[此:d,C,B,A。

    在所有的变型中,被const两种方式使用D中的第一个const]

    这意味着返回的对象不能用于修改返回的对象。这句话听起来很有趣,不是吗?那么,可能有其他方法来修改对象,而这const不能阻止。看到这个FAQ item

  • 类不变[在d第二const]

    这意味着该方法不发生变异(修改)类对象。

我比D更喜欢D,因为D保证调用该方法的对象不会被修改。如果一个目标可以实现(即方法可以实现)而不需要修改一个目标,这在设计方面是一个巨大的胜利。我可以随时使用它。 但是如果对象必须被修改(即没有方法可以在不修改对象的情况下实现),则排除D.

其中,B和C都优于A,因为B和C返回一个引用,它避免了A中所需的复制构造。

在B和C之间,C是可取的,因为它返回const参考。

+1

但他们有不同的语义。从我的角度来看,唯一有意义的(在大多数情况下)是B和D.你也可以考虑'string ToString()const;'。 B只在你想让用户修改字符串时才有用。如果您只是要返回对“MyClass”的字符串成员的引用,则首选D。如果字符串不是成员(即在函数调用期间计算),请使用上面的表格。 C的一个可能用途是如果MyClass必须计算字符串,但将其作为成员变量缓存(因此不是const)。然而,那么你应该使用'可变' – Gretchen 2010-10-15 06:37:57

+0

是的,我也会在几乎所有情况下避免选项C.独自一人是有道理的。定义_both_ B和D是有意义的,如果你想要版本B.如果字符串是在函数调用时计算的,而不是简单的成员,那么版本A是合理的。 – aschepler 2010-10-15 16:00:33

相关问题