简体   繁体   English

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

[英]Constructor called on an already created object

If I call a constructor on an already constructed object or struct, will it allocate new space, or just use the existing space? 如果我在已经构造的对象或结构上调用构造函数,它会分配新空间,还是只使用现有空间? So is the first object allocation more resource intensive? 那么第一个对象分配是否更加资源密集? Like this: 像这样:

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)

Is the constructor call more resource intesive, than the call to a function which does the same ( void a(...) )? 构造函数是否调用了更多的资源,而不是对函数调用( void a(...) )?

Does the destructor gets called, when I call a constructor on an already created object? 当我在已经创建的对象上调用构造函数时,是否会调用析构函数?

First off, the [c] tag is inappropriate since constructors are a C++-only feature. 首先, [c]标签是不合适的,因为构造函数是仅限C ++的特性。 I'll assume the code snippet you provided is in fact C++ and not some weird dialect of C. C++ and C are different languages ; 我假设你提供的代码片段实际上是C ++而不是C. C ++和C的一些奇怪的方言是不同的语言 ; do not tag your questions as both since you will get different answers for each. 不要将你的问题标记为两者,因为你会得到不同的答案。

Second, your constructor definition is wrong. 其次,构造函数定义是错误的。 Constructors must have the exact same name as the class itself. 构造函数必须与类本身具有完全相同的名称。 So f() should've been F() . 所以 f()应该是 F() Yes, case-sensitivity matters in C++! 是的,区分大小写在C ++中很重要! I'll assume this is what you meant for the rest of the code snippet. 我假设这是你对其余代码片段的意思。 OP simply made a typo. OP只是打错了。

Before I explain what the rest of your code does, you must understand that all classes (and structs) in C++ have special member functions that are automatically generated by the compiler if you don't provide them. 在我解释其余代码的作用之前,您必须了解C ++中的所有类(和结构)都有特殊的成员函数 ,如果您不提供这些函数 ,则由编译器自动生成。 That is, your code snippet is basically the same as: 也就是说,您的代码段基本上与以下内容相同:

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

If you do not define a copy constructor, a copy assignment operator, or a destructor, the compiler will generate them for you. 如果未定义复制构造函数,复制赋值运算符或析构函数,编译器将为您生成它们。 Also, if you don't provide some other constructor, the compiler will generate a default constructor. 此外,如果您不提供其他构造函数,编译器将生成默认构造函数。 There is no default constructor for class F since there's already a (non-copy) constructor that accepts two arguments. F类没有默认构造函数,因为已经有一个(非复制)构造函数接受两个参数。

The default implementation of the copy constructor and the copy assignment operator simply copies each data member. 复制构造函数和复制赋值运算符的默认实现只是复制每个数据成员。

The reason why special member functions exist is because C++ generalizes the notion of copying primitive types to user defined objects. 特殊成员函数存在的原因是因为C ++概括了将基元类型复制到用户定义对象的概念。 Consider this: 考虑一下:

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

With primitive types like int s, you can copy around its value just like that. 对于像int的原始类型,你可以像这样复制它的值。 C++ generalizes the copy semantics to objects so you can do this: C ++将复制语义概括为对象,因此您可以这样做:

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

Now you can see how this applies to your code: 现在您可以看到这对您的代码有何影响:

F f = F(5,6); 

The line above constructs a temporary F object, then copies the temporary into f via the copy constructor. 上面的行构造一个临时F对象,然后通过复制构造函数将临时副本复制到f The temporary F object is then destructed. 然后破坏临时F对象。

f = F(7,8);

The line above constructs another temporary F object, then assigns the temporary into f via the copy assignment operator. 上面的行构造另一个临时F对象,然后通过复制赋值运算符将临时值分配给f The temporary F object is then destructed. 然后破坏临时F对象。 The original f object is not destructed. 原始f对象未被破坏。

f.a(9,0)   

The line above is a normal function call on an object called f . 上面的行是对名为f的对象的正常函数调用。

For your code snippet, assuming compilers do not optimize away the temporaries (they in fact usually do), then calling the function a is "less resource intensive" since no temporaries are made in that case. 对于你的代码片段,假设编译器没有优化临时(他们实际上通常这样做),那么调用函数a “资源消耗较少”,因为在这种情况下不会产生临时值。 However, for your first constructor call, you can just do this: 但是,对于第一个构造函数调用,您可以这样做:

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

Understand what constructors are used for: they are used to create objects . 了解构造函数的用途: 它们用于创建对象 If you already have an object, then you don't need to call a constructor. 如果您已有对象,则无需调用构造函数。

As I have recommended many times, please pick up a good C++ book and read it. 正如我多次推荐的那样,请选一本好的C ++书并阅读。 Special member functions and what they do are quite fundamental to C++. 特殊的成员函数及其所做的是C ++的基础。

(In the code you posted you've used a lower-case f instead of an upper-case F for the constructor, which I assume is a typo) (在您发布的代码中,您使用了小写的f代替构造函数的大写F,我认为这是一个错字)

Your question is interesting because the question you've asked and the code you've written are not the same. 你的问题很有趣,因为你问的问题和你写的代码是不一样的。 In the code, you've written 在代码中,你写了

f = F(7, 8);

This does call the F constructor, but not on the existing f object. 这会调用F构造函数,但不会调用现有的f对象。 Instead, this creates a temporary F object initialized by calling tue constructor with 7 and 8 as arguments, then uses the assignment operator to set the existing f variable equal to this new object. 相反,这会创建一个临时F对象,通过调用tue构造函数初始化,使用7和8作为参数,然后使用赋值运算符将现有f变量设置为等于此新对象。 Consequently, the constructor is not invoked twice on the object; 因此,构造函数不会在对象上调用两次; instead it's the assignment that gets called here. 相反,这是在这里调用的赋值。 More generally, if you ever assign an existing object a new value, the assignment operator, not a constructor, will be used to do the copying. 更一般地说,如果您为现有对象分配新值,则将使用赋值运算符而不是构造函数进行复制。 This will reuse the existing memory for the object, though it may trigger auxiliary memory allocations and deallocations. 这将重用对象的现有内存,但它可能会触发辅助内存分配和解除分配。

There is no safe way to invoke an object's constructor twice. 没有安全的方法可以两次调用对象的构造函数。 If you really do want to invoke the constructor of an object that's already been created, you can do so using placement new: 如果您确实想要调用已创建的对象的构造函数,则可以使用placement new来执行此操作:

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

This is unsafe as it bypasses typical resource cleanup the destructors normally would do and blindly overrides the existing elements, so this is almost never done in practice. 这是不安全的,因为它绕过了析构函数通常会做的典型资源清理,并盲目地覆盖现有元素,因此这几乎从未在实践中完成。 I mention it mostly for the sake of curiosity and for completeness. 我提到它主要是为了好奇和完整。 :-) :-)

i'm ignoring the implementation in the OP, and going straight to the QA: 我忽略了OP中的实现,并直接进入质量保证:

if i call a constructor on an already constructed object / struct, will it allocate new space 如果我在已经构造的对象/结构上调用构造函数,它是否会分配新的空间

no, the object will not be reallocated. 不,该对象不会被重新分配。 the constructor's implementation will be called (eg a function call). 将调用构造函数的实现(例如函数调用)。

So is the first object allocation more resource intensive? 那么第一个对象分配是否更加资源密集?

you should generally not do this, unless you're implementing a collection (eg vector ). 你通常不应该这样做,除非你正在实现一个集合(例如vector )。

but, to answer the question: yes, the second will require fewer instructions. 但是,要回答这个问题:是的,第二个将需要更少的指令。 the compiler produces trivial instructions to set up the allocation (if on the stack or elsewhere). 编译器生成简单的指令来设置分配(如果在堆栈或其他地方)。 so there really is a few stages to creating an object automatically, and you are bypassing some of that. 所以真的有几个阶段自动创建一个对象,你绕过了其中的一些。 but seriously: don't consider this as an optimization -- only call the constructor/destructor manually if you absolutely must (again, think collection types). 但严重的是:不要将此视为优化 - 如果绝对必须(再次考虑集合类型),则仅手动调用构造函数/析构函数。

Is the constructor call more res. 构造函数是否调用更多res。 intesive, than the call to a function which does the same (void a(...)) ? intesive,而不是调用一个相同的函数(void a(...))?

potentially, the compiler's efforts also weigh in. remember, constructors and destructors call the implementation of each class in the hierarchy, so... it's quite likely that a singular function would be faster if your class hierarchy is non-trivial. 可能,编译器的努力也在考虑。记住,构造函数和析构函数调用层次结构中每个类的实现,因此......如果类层次结构非常重要,那么单个函数很可能会更快。

Does the destructor gets called, when i call a constructor on an already created object? 当我在已创建的对象上调用构造函数时,是否会调用析构函数?

if you explicitly construct an object in this manner, then the answer is 'no'. 如果以这种方式显式构造对象,则答案为“否”。 it's your job to appropriately pair the explicit invocations. 适当配对显式调用是你的工作。 you cannot afford to implement this incorrectly, it's as good as UB. 你不能错误地实现这个,它和UB一样好。 the order is always construct->destruct . 顺序总是construct->destruct

just to be clear of the syntax used: 只是为了清楚使用的语法:

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

There are syntatic mistakes in your program, modifying your snippet- 您的程序中存在合成错误,修改您的代码段 -

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

Destructor gets called, when the constructed object goes out of scope ( ie., when the life time of the object completes). 当构造的对象超出范围时(即,当对象的生命周期完成时),将调用析构函数。

Your class F does not have a constructor but only a method f. 你的类F没有构造函数,只有方法f。 So, no constructor is called at any time. 因此,任何时候都不会调用构造函数。

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

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