构造函数调用已创建的对象

时间:2011-02-18 08:10:39

标签: c++ memory constructor allocation

如果我在已经构造的对象或结构上调用构造函数, 它会分配新空间,还是只使用现有空间?那么第一个对象分配是否更加资源密集?像这样:

struct F {
    int a,b,c,d;
    F(int _a, int _b) {a = _a; b = _b}; 
    void a(int _a, int _b) {a = _a; b = _b};
};  

//first constructor call
F f = F(5, 6);

//second constructor call on an already constructed object
f = F(7, 8);

//third constructor call on an already constructed object
f(7, 8);

//is the constructor call more res. intesive, than the call to a function which does the same? 
f.a(9, 0)

构造函数是否调用了更多的资源,而不是调用执行相同操作的函数(void a(...))?

当我在已经创建的对象上调用构造函数时,是否会调用析构函数?

5 个答案:

答案 0 :(得分:7)

首先,[c]标记是不合适的,因为构造函数是仅限C ++的特性。我假设你提供的代码片段实际上是C ++,而不是C的一些奇怪的方言。 C ++和C是不同的语言;不要将你的问题标记为两者,因为你会得到不同的答案。

其次,构造函数定义错误。构造函数必须与类本身具有完全相同的名称。所以f()应该是F()。是的,区分大小写在C ++中很重要!我会假设这是你对其余代码片段的意思。 OP只是打错了。

在我解释代码的其余部分之前,您必须了解C ++中的所有类(和结构)都有special member functions,如果您不提供它们,它们将由编译器自动生成。也就是说,您的代码段基本上与:

相同
struct F
{
    F(int _a, int _b) {a = _a; b = _b};  // constructor
    ~F() {}                              // destructor
    F(const F& rhs)                      // copy constructor
        : a(rhs.a)
        , b(rhs.b)
        , c(rhs.c)
        , d(rhs.d)
    {}
    F& operator=(const F& a)             // copy assignment operator
    {
        a = rhs.a;
        b = rhs.b;
        c = rhs.c;
        d = rhs.d;
        return *this;
    }

    void a(int _a, int _b) {a = _a; b = _b};   // one of your functions

    int a;
    int b;
    int c;
    int d;
};

如果没有定义复制构造函数,复制赋值运算符或析构函数,编译器将为您生成它们。此外,如果您不提供其他构造函数,编译器将生成默认构造函数。类F没有默认构造函数,因为已经有一个(非复制)构造函数接受两个参数。

复制构造函数和复制赋值运算符的默认实现只是复制每个数据成员。

存在特殊成员函数的原因是因为C ++概括了将基元类型复制到用户定义对象的概念。考虑一下:

int a = 42;
int b = 13;
b = a;

对于像int这样的原始类型,您可以像这样复制其值。 C ++将复制语义概括为对象,因此您可以这样做:

F f(10, 20); // calls first constructor
F g(30, 40); // calls first constructor
g = f;       // calls g's copy-assignment operator.

现在您可以看到这对您的代码有何影响:

F f = F(5,6); 

上面的行构造了一个临时的F对象,然后通过复制构造函数将临时副本复制到f。然后破坏临时F对象。

f = F(7,8);

上面的行构造了另一个临时F对象,然后通过复制赋值运算符将临时值分配到f。然后破坏临时F对象。原始的f对象被破坏。

f.a(9,0)   

上面的行是对名为f的对象的正常函数调用。

对于你的代码片段,假设编译器没有优化临时值(实际上它们通常都是这样),那么调用函数a“资源消耗较少”,因为在这种情况下不会产生临时值。但是,对于第一个构造函数调用,您可以这样做:

F f(5,6); // Constructor called; no temporaries are made

了解构造函数的用途:它们用于创建对象。如果您已有对象,则无需调用构造函数。

正如我多次推荐的那样,请选择good C++ book并阅读。特殊的成员函数及其所做的是C ++的基础。

答案 1 :(得分:3)

(在您发布的代码中,您使用了小写的f代替构造函数的大写F,我认为这是一个错字)

您的问题很有趣,因为您提出的问题和您编写的代码并不相同。在代码中,您已经编写了

f = F(7, 8);

这会调用F构造函数,但不会调用现有的f对象。相反,这会创建一个临时F对象,通过调用tue构造函数初始化,使用7和8作为参数,然后使用赋值运算符将现有f变量设置为等于此新对象。因此,构造函数不会在对象上调用两次;相反,这是在这里调用的赋值。更一般地说,如果您为现有对象分配新值,则将使用赋值运算符而不是构造函数进行复制。这将重用对象的现有内存,但它可能会触发辅助内存分配和解除分配。

没有安全的方法来调用对象的构造函数两次。如果您确实想要调用已创建的对象的构造函数,则可以使用placement new来执行此操作:

F f(3, 5);
new (&f) F(7, 9);

这是不安全的,因为它绕过了析构函数通常会执行的典型资源清理,并盲目地覆盖了现有元素,所以这几乎从未在实践中完成。我提到它主要是为了好奇和完整。 :-)

答案 2 :(得分:2)

我忽略了OP中的实现,直接进入质量保证:

  

如果我在已构造的对象/结构上调用构造函数,它是否会分配新的空间

不,该对象不会被重新分配。将调用构造函数的实现(例如函数调用)。

  

第一个对象分配是否更加耗费资源?

除非您正在实施集合(例如vector),否则通常不应这样做。

但是,回答这个问题:是的,第二个将需要更少的指令。编译器生成简单的指令来设置分配(如果在堆栈或其他地方)。所以真的有几个阶段自动创建一个对象,你绕过了其中的一些。但严重的是:不要将此视为优化 - 如果绝对必须(再次考虑集合类型),则仅手动调用构造函数/析构函数。

  

构造函数是否调用更多res。 intesive,而不是调用一个相同的函数(void a(...))?

潜在地,编译器的努力也在考虑。记住,构造函数和析构函数调用层次结构中每个类的实现,因此......如果类层次结构非常重要,那么单个函数很可能会更快。

  

当我在已经创建的对象上调用构造函数时,是否会调用析构函数?

如果以这种方式显式构造对象,则答案为“否”。适当配对显式调用是你的工作。你不能错误地实现这个,它和UB一样好。订单始终为construct->destruct

只是要清楚使用的语法:

// explicit ctor
new(ptr) T(ctorArgument);
// explicit dtor
ptr->~T();

答案 3 :(得分:1)

您的程序中存在合成错误,修改了代码段

struct F {

    int a,b,c,d;

    F(int _a, int _b) {a = _a; b = _b}; 

    void a(int _a, int _b) {a = _a; b = _b};

};

F f = F(5,6); // Here the default copy constructor gets called.
              // i.e., F( const F& obj ) ;

f = F(7,8);   // A temporary is created is assigned to `f` through default copy assignment operator.
              // i.e., F& operator=( const F& obj );

当构造的对象超出范围时(即,当对象的生命周期完成时),析构函数被调用。

答案 4 :(得分:0)

你的F类没有构造函数,只有f方法。因此,任何时候都不会调用构造函数。