在构造函数或 init 函数中分配内存?

问题描述

我是 C++ 新手,我有一个类保存了一些内存,类看起来像:

class MyClass
{
public:
    MyClass (int s)
    {
        if (s <= 0) _size = 1;
        else _size = s;

        data = new int[_size];  // may throw exception
    }


private:
    int *data;
    int _size;
};

据我所知,在构造函数中抛出异常是不安全的,所以我把 malloc 放到了一个 init 函数中。


class MyClass
{
public:
    MyClass (int s)
    {
        if (s <= 0) _size = 1;
        else _size = s;
    }

    void init()
    {
        data = new int[_size];
    }


private:
    int *data;
    int _size;
};

我的问题:

  1. 在构造函数或init函数中分配内存,哪个更好
  2. 如果我选择了init函数,如何保证init函数调用其他成员函数之前已经调用过?

解决方法

据我所知,在构造函数中抛出异常是不安全的,所以我把 malloc 放到了一个 init 函数中。

不,这不是“不安全”。这是使构造函数失败的方法。您可能正在考虑析构函数中止或其他有关异常安全保证的问题。

“Init”函数为构造函数引入了两阶段方法,这增加了复杂性。除非您需要在没有例外的环境中工作,否则请避免使用它们。在这种情况下,工厂函数是另一种处理方式。

在构造函数或init函数中分配内存,哪个更好

构造函数。请参阅std::vector

如果我选择了init函数,如何保证init函数在调用其他成员函数之前已经调用过?

静态地,如果没有运行时检查或外部工具,您就无法做到。

您可以在 init 函数上设置一个标志,然后检入每个成员函数。

,

如果我选择了init函数,如何保证init函数在调用其他成员函数之前已经调用过?

你不能,这是一个大问题!您在这里偶然发现了一个名为 Resource Acquisition is Initialisation (RAII) 的概念。这大致就是您在第 1 部分中编写的内容。如果添加析构函数:

~MyClass() {
    delete[] data;
}

然后,您已经开始着手开发最有用的 C++ 容器之一,std::vector。这与您在这里尝试实现的目标类似。

甚至还有一个 cpp 核心指南:A constructor should create a fully initialised object

据我所知,在构造函数中抛出异常是不安全的

实际上这是不真实的。事实上,下一个核心准则是If a constructor cannot construct a valid object,throw an exception

TLDR:使用选项一,在这种情况下 init 不好。

,

构造函数的要点是您可以确保在任何其他成员函数之前调用构造函数。

Init 函数来自 c,不被认为是最佳实践

,

除了上面的有效答案之外,您还可以考虑使用现有的标准库类来“封装”内存的分配和解除分配:std::unique_ptr<int>。使用它可以省去您实现一堆方法的需要(例如复制构造函数、移动构造函数、赋值运算符和析构函数;参见 rule of five)。

此外,std::size_t 更适合存储分配的内存量。

最后,以 _ 开头的名称通常是保留的,我们避免使用它们。

所以:

#include <memory>

// ...

class MyClass {
public:
    using size_type = std::size_t;
    using value_type = int;

    MyClass (size_type size) :
        size_(std::max<size_type>(size,1)),data_(std::make_unique<value_type[]>(size_))
    { }

    // etc. etc. - but no need for copy ctor,move ctor,assignments and dtor

private:
    std::unique_ptr<value_type[]> data_;
    size_type size_;
};

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...