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

C++ c++;这个问题的问题在哪里?(带参数的构造函数),c++,C++,假设string类有如下私有数据成员: char *strval; int length; string::string(const char* s):length(strlen(s)) { strval = s; } 字符串类的以下构造函数代码正确吗?如果不正确,原因是什么? char *strval; int length; string::string(const char* s):length(strlen(s)) { strval = s; } 我的回

假设string类有如下私有数据成员:

char *strval; 
int length; 
string::string(const char* s):length(strlen(s)) 
{ 
strval = s; 
} 
字符串类的以下构造函数代码正确吗?如果不正确,原因是什么?

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

我的回答是strlen()正在计算指针值,但这听起来是错误的。

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

  • 一个成员使用初始化器列表初始化,而另一个成员在构造函数中分配(这是不一致的)
  • 未检查
    s
    是否为
    NULL
    (但这可能被记录为非法输入)
  • 如果不制作字符串的副本,则单独存储指针和长度是多余的(因为它们可能会不同步)

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

  • 一个成员使用初始化器列表初始化,而另一个成员在构造函数中分配(这是不一致的)
  • 未检查
    s
    是否为
    NULL
    (但这可能被记录为非法输入)
  • 如果不制作字符串的副本,则单独存储指针和长度是多余的(因为它们可能会不同步)

代码不正确,甚至无法编译
strval=s
将失败,因为
strval
是指向
const
的指针,而
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; 
}

@格雷格的观点仍然有效。我只是强调一个要点。

代码不正确,甚至无法编译
strval=s
将失败,因为
strval
是指向
const
的指针,而
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; 
}

@格雷格的观点仍然有效。我只是强调一个要点。

字符串可能有三种合理的工作方式,但正如前面介绍的,它不属于这三种类型中的任何一种。它们是:

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

  • a
    (常量字符*,长度)
    常量 “参考”指的是 调用者,这保证了 文本的生存期将长于 “字符串”的用法

  • a
    (字符*,长度)
    参考 服务器拥有的可写缓冲区 调用者,但“字符串”插入其中 对象可能会进行更新(可能是 即使移动NUL终结者)

  • 我们可以依次考虑每个问题。

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

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

    int length;  // should really be size_t
    char *strval;
    
    …以便构造函数可以使用初始化列表,并知道将首先填充长度值,因此可用于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\u reference
    substring\u reader
    或任何适合您的名称

    3.对文本的非常量引用 显示的
    strval
    指针不是
    const
    ,它表示一个对象能够覆盖提供的缓冲区的内容,但仍然不能延长缓冲区。这在我的经验中很少有用,尽管它可能非常适合某些特定项目的需要。应该为这样的类找到更好的名称,这并不容易!,但是,例如“缓冲区覆盖器”提示——至少在我看来——长度上限和非constaccess。此外,所提供的构造函数仅适用于已经以NUL终止的缓冲区,但我们可以想象第二个构造函数
    (char*,int)
    ,它删除了该要求,并可能使对象更广泛地有用

    否则,Greg将覆盖t