繁体   English   中英

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

[英]Constructor called on an already created object

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

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(...) )?

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

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

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

在我解释其余代码的作用之前,您必须了解C ++中的所有类(和结构)都有特殊的成员函数 ,如果您不提供这些函数 ,则由编译器自动生成。 也就是说,您的代码段基本上与以下内容相同:

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

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

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

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

你的问题很有趣,因为你问的问题和你写的代码是不一样的。 在代码中,你写了

f = F(7, 8);

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

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

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

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

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

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

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

那么第一个对象分配是否更加资源密集?

你通常不应该这样做,除非你正在实现一个集合(例如vector )。

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

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

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

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

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

只是为了清楚使用的语法:

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

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

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 );

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM