1

我正在实现一个类request,它的构造函数将命令行作为其参数,并且该类将文件状态(如文件大小、上次修改时间等)作为其字段。

我想为这些字段分配值,它涉及调用fstat()、访问 中的值struct stat以及使用这些值。

我知道不鼓励 c++ 构造函数中的赋值,并且应该使用初始化列表,但我不知道如何在不调用构造函数主体(括号之间)和使用赋值运算符的情况下为这些字段赋值。

我该怎么办?

如果我必须在构造函数主体中初始化它们,我应该首先使用初始化所有字段NULL(我认为这是默认完成的)吗?


class request {
    vector<string> requests;
    off_t content_length;
    char* last_modified;

    public:

    explicit request(char line[]): requests(split_string(line)), content_length(NULL), last_modified(NULL) {
        struct stat sb;
        if(fstat(line[1], &sb) == -1) {
            cerr << "Error while getting file status of the file named " << line[1] << endl;
        }

        content_length = sb.st_size;
        last_modified = ctime(&sb.st_mtime);
    }
};

这是我的代码。他们看起来好吗?

4

3 回答 3

2

作业本身并没有错。建议使用初始化列表的原因是为了构造“昂贵”的成员,因为在构造函数主体中分配的情况下,您需要支付两次费用:一次使用默认构造函数构造成员,然后分配给它。

因此,如果您有一个难以用简单表达式初始化的特殊成员,请不要为此而自杀 - 在主体中初始化它。您可能想要做的一件事是使其(即该成员的)默认构造函数便宜,这将消除问题。

还有与这两种方法相关的异常处理内涵,但我认为它们与您的情况无关。

于 2013-10-22T20:50:20.620 回答
2

对成员使用初始化列表比在构造函数中赋值有几个优点:

  • 带有构造函数的成员变量只构造一次。
  • const这是初始化成员的唯一方法。

但是,如果初始化太复杂而无法在构造函数中进行,那么在主体中进行初始化并没有错。

默认情况下,成员初始化为 NULL。具有构造函数(即非 POD 类型)的成员变量是默认初始化的,仅此而已。

进行复杂初始化并仍在初始化器列表中进行的一种方法是使用辅助函数。

Example::Example()
  : file_size_(CalculateFileSize())
{
};

int Example::CalculateFileSize()
{
  // Complex initialization here.
  // Be careful - this instance isn't fully initialized yet.
}

这种方法通常不如仅在构造函数主体中执行它那么清晰,因此我只建议您确实需要在初始化器列表中执行所有操作(例如,如果您正在使用const成员变量)。另请注意,您一次只能干净地使用它来初始化一个成员变量。

于 2013-10-22T20:56:05.653 回答
2

构造函数体没有任何问题,尤其是在您的程序中允许异常的情况下。这里更重要的规则是 RAII。

我会做类似以下的事情:

class request
{
  public:
    request (int fildes)
      : size(0)
      , last_modified_time(EPOCH)
    {
      struct stat statistics;
      auto error = fstat(&statistics);

      if (not error) {
          size = statistics.st_size;
          last_modified_time = statistics.st_mtimespec;
          // ...
      } else {
          // Note: if exceptions are not okay for you, then you need to move this
          // entire body to an Initialize() function that returns an error
          // indicator. This pattern is called two-phase initialization.
          //
          throw std::runtime_error("Hard disk is broken?!");
      }
    }
}
于 2013-10-22T20:57:55.917 回答