有什么方法可以避免在c ++构造函数体中赋值?

时间:2013-10-22 20:46:28

标签: c++ constructor

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

我想为这些字段分配值,包括调用fstat(),访问struct stat中的值,并使用这些值。

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

我该怎么办?

如果我必须在构造函数体中初始化它们,我应该首先使用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);
    }
};

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

3 个答案:

答案 0 :(得分:2)

作业本身没有任何问题。 推荐使用初始化列表的原因是构造成本“昂贵”的成员,因为如果在构造函数体中分配,则需要支付两次:一次使用默认构造函数构造成员,然后分配给它。

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

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

答案 1 :(得分:2)

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

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

但是,如果初始化过于复杂而无法在构造函数中进行,那么在正文中初始化没有错误

默认情况下, 成员初始化为NULL。具有构造函数的成员变量(即非POD类型)是默认初始化的,但这就是全部。

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

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

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

这种方法通常不像在构造函数体中那样清晰,所以我只推荐它,如果你真的需要在初始化列表中做所有事情(例如,如果你使用{{1}成员变量)。另请注意,您一次只能干净利用它来初始化一个成员变量。

答案 2 :(得分: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?!");
      }
    }
}