在C ++构造函数中使用自动变量

时间:2014-09-03 23:01:17

标签: c++ memory-management constructor

所以我读到使用new意味着您手动必须管理内存而使用自动变量意味着当变量超出范围时它将被删除。这如何与构造函数一起工作?如果我使用自动变量创建对象,是否会保存?

例如,如果我有一个班级:

class University{
    Student s;
public:
    University(int id, char* name){
        Student x(id, name);
        s = x;
    }
};

这会有用吗? (假设我为Student类设置了一个正确定义的复制构造函数)。如果这确实有效,为什么有人会想要new呢?我对C ++很新,所以如果这是一个愚蠢的问题,请道歉。

4 个答案:

答案 0 :(得分:4)

是的,它有效。 s首先获取默认构造,然后仅在成功构造x时进行复制分配。如果引发异常并且它逃脱了University构造函数,则sx如果成功构建,则会被破坏。

话虽这么说,写这个的最好方法是根本不创建x,并在s构造函数的初始化列表中初始化University

class University
{
private:
    Student s;

public:
    University(int id, char* name)
        : s(id, name)
    {
    }
};

话虽如此,你的问题是new。等价物如下所示:

class University
{
private:
    Student *s;

public:
    University(int id, char* name)
        : s(new Student(id, name))
    {
        try
        {
            // do something that might throw an exception
        }
        catch (...)
        {
            delete s;
            throw;
        }
    }

    ~University()
    {
        delete s;
    }
};

try/catch的原因是因为如果构造函数抛出异常,则不会调用析构函数。

以上内容可以使用自动变量替换为以下内容:

class University
{
private:
    std::auto_ptr<Student> s; // or std::unique_ptr if you are using C++11

public:
    University(int id, char* name)
        : s(new Student(id, name))
    {
    }
};

无论是否抛出异常,s如果成功构建都将被破坏。

答案 1 :(得分:3)

  

这会有用吗?

是的,它会起作用,但通过x使用

进行间接
Student x(id, name);
s = x;

在构造函数体中,完全没必要!我要做的是,只是为了压缩构造函数体代码,并避免引用初始化问题,使用member initializer list

class University{
    Student s;
public:
    University(int id, char* name) : s(id,name) {
                                // ^^^^^^^^^^^^ Use member initializer list!
    }
}; 

您不需要构造函数体中的中间实例。

  

如果这确实有效,为什么有人想在这上面使用new?

哎呀,没有办法告诉你,恕我直言。有时对于某些用例/需求,可能需要在堆上创建Student的实例,而不是使用堆栈分配的实例。


ATTENTIVELY NOTE:

你在这里发布的所有内容,从语义的角度看都是非常错误的: - / ...

University通常有很多 Student订阅,而不只是一个!这意味着您需要在University个实例中保留学生列表 你应该考虑使用像

这样的东西
class University {
    std::vector<Student> students_;
    std::string universityName_;
public:
    University(std::string universityName) : universityName_(universityName) {}
    void addStudent(const Student& newStudent) {
       students_.push_back(newStudent);
    }
    void addStudent(int id, const char* name) {
       students_.push_back(Student(id,name));
    }
};

答案 2 :(得分:1)

您的代码的天真解释是x是University(...)构造函数堆栈上的自动对象。当构造函数调用结束时,x对象将被销毁。 但是,您也将x对象分配给s,并且s被声明为大学对象的成员变量,天真地说,它将保留它。

(除非为Student类重新定义=运算符以执行异常操作。)

如果您使用推荐的初始化列表

University(int id, char* name)
    : s(id, name)
{
}

, 语义将有所不同,因为s将直接从(id, name)构建。 如果你像那样分配它,那么s将首先用它的默认构造函数构造,如果它有一个,然后从x变量赋值。

答案 3 :(得分:-1)

是的,那会有效。您正在创建一个临时学生,然后将其复制到s,即大学课程成员的学生对象。 只要有大学课程的实例,其成员也可以使用。 以下是使您的计划更好的几点建议:

  1. 使用std :: string而不是char *
  2. 在大学构造函数中传递学生对象毫无意义,在我看来,添加addStudent方法是一种更好的方法
  3. 传递const对象引用,而不是基元,它是更好的样式(更多封装),因为引用更有效率
  4. 例如:

    class University{
        Student s;
    public:
        University(){}
        void addStudent(const Student& newStudent){
            s = newStudent;
        }
    
    };