首页 > 解决方案 > 在构造函数的主体中证明分配效率低下

问题描述

我在http://www.cs.technion.ac.il/users/yechiel/c++-faq/init-lists.html中读到 ,使用初始化列表比在构造函数的主体中进行分配更有效,因为例如在Fred::Fred() { x_ = whatever; }

1) 导致创建一个单独的临时对象的表达式,并且这个临时对象被传递给 x_ 对象的赋值运算符。然后该临时对象在 ; 处被销毁。

2)成员对象将由其默认构造函数完全构造,例如,这可能会分配一些默认数量的内存或打开一些默认文件

赋值如何导致在构造函数中创建一些临时对象?这意味着构造函数会调用自己:无限递归调用

我制作了以下代码来验证在分配过程中创建了对象的副本,希望看到临时对象的额外创建和销毁,但我只能看到我正在创建的对象的创建和销毁main 当然没有无限递归调用。如何理解它以及如何修改代码以查看临时对象的创建和销毁?

#include<iostream>
using namespace std;

class Base
{
    private:
    int c_var;
    public:
    Base( )
    {   c_var=10;
        cout <<"Constructor called"<<endl;
        cout << "Value is " << c_var<<endl;
    }
    ~Base()
    {
        cout <<"Destructor called"<<endl;
    }
};

int main()
{
    Base il;
}

标签: c++oopconstructor

解决方案


赋值如何导致在构造函数中创建一些临时对象?这意味着构造函数会调用自己:无限递归调用

没有。文中谈到调用成员的构造函数。有了int它并没有太大关系,但请考虑:

struct foo {
    foo() { 
        /* construct a foo, with expensive instructions */ 
        std::cout << "default constructor";
    }
    foo(int x) { 
        /* also construct a foo */ 
        std::cout << "constructor";
    }
};

struct bar_wrong {
    foo f;
    bar_wrong() { 
        f = foo(42);
    }
};

在执行构造函数的主体之前初始化成员。因此,foo成员bar_wrong将首先被默认构造(这可能很昂贵),稍后会被正确的实例覆盖并创建 abar_wrong将打印来自foos 构造函数的两个输出。

正确的方法是

struct bar_correct {
    foo f;
    bar_correct() : f(42) {}
};

因为这里foo只是初始化。或者,您可以使用类内初始化程序:

struct bar_alternative {
    foo f{42};
};

这里编译器生成的构造函数就足够了。它将使用类内初始化程序进行f初始化42


推荐阅读