c ++这个问题的问题在哪里? (带参数的构造函数)

时间:2011-05-22 21:39:00

标签: c++

假设字符串类具有以下私有数据成员:

char *strval; 
int length; 

以下字符串类的构造函数代码是否正确?如果不正确,为什么?

string::string(const char* s):length(strlen(s)) 
{ 
strval = s; 
} 

<击> 我的回答是strlen()正在评估指针值,但这听起来不对。

3 个答案:

答案 0 :(得分:7)

给出的构造函数代码是正确的,因为它将为大多数输入成功编译和运行。然而,至少有几个原因,它的风格很差:

  • 使用初始化列表初始化一个成员,而在构造函数中分配另一个成员(这是不一致的)
  • 未检查s是否为NULL(但这可以记录为非法输入)
  • 如果您没有复制该字符串,则单独存储指针 length 是多余的(因为它们可能会不同步)< / LI>

答案 1 :(得分:2)

代码不正确,甚至无法编译。 strval=s会失败,因为strvalconst的指针,s不是。以下是一个更好的起点:

class string
{
    const char *strval; // This must be const for 'strval = s' to work.
    int length;
    string (const char *s);
};

string::string(const char* s):length(strlen(s)) 
{ 
    strval = s; 
}
@Greg的观点仍然有效。我只是强调一个重点。

答案 2 :(得分:1)

字符串可以合理地工作有三种方式,但是如上所述,它不属于三种类别中的任何一种。他们是:

  1. 一个“价值语义”对象 复制指定的数据和 保持对它的所有权,就像 std::string

  2. 一个(const char*, length) const 对某些文本的“引用” 调用者,保证 文本的生命周期将长于 “字符串”的用法

  3. (char *, length)的引用 一个可写的缓冲区 调用者,但其中的“字符串” 对象可能会更新(也许 甚至移动NUL终结器)

  4. 我们可以依次考虑每一个。

    1。根据`std :: string`

    的值语义

    这个问题非常明确地指出这是一个“字符串”类,这意味着(弱,但我们没有太多东西要去......)该类旨在作为通用值语义字符串。假设当下是真的,我们可以考虑所呈现的实现:该类只记住调用者指定的非const字符缓冲区的地址和长度,而不占用缓冲区的所有权。即使从调用者的角度来看,字符串类被赋予该缓冲区的所有权(即调用者不会在不经过字符串API的情况下进一步修改内容),也没有证据表明字符串对象具有增长缓冲区的方法,这是通用字符串类的基本要求。

    因此,如果它是一个通用字符串,那么它应该复制该值并取得所有权。最好通过重新安排数据成员来完成:

    int length;  // should really be size_t
    char *strval;
    

    ...以便构造函数可以使用初始化列表并知道length的值将首先填充,因此可用于strval的初始化 - 这样就无需计算字符串长度两次......

    string(const char* p, int n)
      : length(strlen(p)), strval(new char[length + 1])
    {
        strcpy(strval, p);
    }
    

    2。对文本的持续引用

    如果字符串意味着是一个通用字符串,那么它的第一个也是最大的问题是名称“string”。为了找到更好的名称,让我们回到所提供的功能。它记住了调用者指定的缓冲区的地址和当前内容长度:根据我的经验,这通常在指针是常量时完成 - 例如,在调用者的字符缓冲区中抽象非NUL终止的子串 - 例如,元素在内存映射文件中的位置。

    第二个问题 - 首先由Aaron发现 - 变成构造函数的字符串参数为const,并且需要更改为char*以允许strval从中进行初始化。或者,如果您将strval更改为const char*,我们将返回到我提到的上述有用的const非NUL终止的子字符串引用。同样,应找到适当的名称,例如text_referencesubstring_reader或任何适合您的工作。

    3。非恒定引用文本

    显示的strval指针不是const,这表示一个对象能够覆盖提供的缓冲区内容,但仍然无法延长缓冲区。这在我的经验中很少有用,尽管它可能是某些特定程序需求的理想选择。应该找到这样一个类的更好的名称,而不是简单!,但是例如“buffer_overwriter”暗示 - 至少在我看来 - 在长度限制的性质和非const访问。此外,提供的构造函数仅适用于已经NUL终止的缓冲区,但我们可以想象第二个构造函数(char*, int)可以删除该需求,并可以使对象更广泛地使用。

    否则,格雷格会彻底解决问题。