如果我在已经构造的对象或结构上调用构造函数, 它会分配新空间,还是只使用现有空间?那么第一个对象分配是否更加资源密集?像这样:
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(...)
)?
当我在已经创建的对象上调用构造函数时,是否会调用析构函数?
答案 0 :(得分:7)
首先,[c]
标记是不合适的,因为构造函数是仅限C ++的特性。我假设你提供的代码片段实际上是C ++,而不是C的一些奇怪的方言。 C ++和C是不同的语言;不要将你的问题标记为两者,因为你会得到不同的答案。
其次,构造函数定义错误。构造函数必须与类本身具有完全相同的名称。所以 OP只是打错了。 f()
应该是F()
。是的,区分大小写在C ++中很重要!我会假设这是你对其余代码片段的意思。
在我解释代码的其余部分之前,您必须了解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方法。因此,任何时候都不会调用构造函数。