C++ 在没有new的情况下在c ++中调用构造函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2722879/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Calling constructors in c++ without new
提问by Nils
I've often seen that people create objects in C++ using
我经常看到人们使用 C++ 创建对象
Thing myThing("asdf");
Instead of this:
取而代之的是:
Thing myThing = Thing("asdf");
This seems to work (using gcc), at least as long as there are no templates involved. My question now, is the first line correct and if so should I use it?
这似乎有效(使用 gcc),至少只要不涉及模板。我现在的问题是,第一行是否正确,如果正确,我应该使用它吗?
回答by JaredPar
Both lines are in fact correct but do subtly different things.
这两行实际上都是正确的,但做的事情略有不同。
The first line creates a new object on the stack by calling a constructor of the format Thing(const char*)
.
第一行通过调用 format 的构造函数在堆栈上创建一个新对象Thing(const char*)
。
The second one is a bit more complex. It essentially does the following
第二个有点复杂。它主要执行以下操作
- Create an object of type
Thing
using the constructorThing(const char*)
- Create an object of type
Thing
using the constructorThing(const Thing&)
- Call
~Thing()
on the object created in step #1
Thing
使用构造函数创建类型对象Thing(const char*)
Thing
使用构造函数创建类型对象Thing(const Thing&)
- 调用
~Thing()
在步骤 #1 中创建的对象
回答by knittl
I assume with the second line you actually mean:
我假设第二行你的意思是:
Thing *thing = new Thing("uiae");
which would be the standard way of creating new dynamicobjects (necessary for dynamic binding and polymorphism) and storing their address to a pointer. Your code does what JaredPar described, namely creating two objects (one passed a const char*
, the other passed a const Thing&
), and then calling the destructor (~Thing()
) on the first object (the const char*
one).
这将是创建新动态对象(动态绑定和多态性所必需的)并将其地址存储到指针的标准方法。您的代码执行 JaredPar 所描述的操作,即创建两个对象(一个传递 a const char*
,另一个传递 a const Thing&
),然后~Thing()
在第一个对象(第const char*
一个)上调用析构函数 ( )。
By contrast, this:
相比之下,这个:
Thing thing("uiae");
creates a static object which is destroyed automatically upon exiting the current scope.
创建一个静态对象,该对象在退出当前作用域时自动销毁。
回答by Douglas Leeder
The compiler may well optimize the second form into the first form, but it doesn't have to.
编译器很可能会将第二种形式优化为第一种形式,但并非必须如此。
#include <iostream>
class A
{
public:
A() { std::cerr << "Empty constructor" << std::endl; }
A(const A&) { std::cerr << "Copy constructor" << std::endl; }
A(const char* str) { std::cerr << "char constructor: " << str << std::endl; }
~A() { std::cerr << "destructor" << std::endl; }
};
void direct()
{
std::cerr << std::endl << "TEST: " << __FUNCTION__ << std::endl;
A a(__FUNCTION__);
static_cast<void>(a); // avoid warnings about unused variables
}
void assignment()
{
std::cerr << std::endl << "TEST: " << __FUNCTION__ << std::endl;
A a = A(__FUNCTION__);
static_cast<void>(a); // avoid warnings about unused variables
}
void prove_copy_constructor_is_called()
{
std::cerr << std::endl << "TEST: " << __FUNCTION__ << std::endl;
A a(__FUNCTION__);
A b = a;
static_cast<void>(b); // avoid warnings about unused variables
}
int main()
{
direct();
assignment();
prove_copy_constructor_is_called();
return 0;
}
Output from gcc 4.4:
gcc 4.4 的输出:
TEST: direct
char constructor: direct
destructor
TEST: assignment
char constructor: assignment
destructor
TEST: prove_copy_constructor_is_called
char constructor: prove_copy_constructor_is_called
Copy constructor
destructor
destructor
回答by Stephen Cross
Quite simply, both lines create the object on the stack, rather than on the heap as 'new' does. The second line actually involves a second call to a copy constructor, so it should be avoided (it also needs to be corrected as indicated in the comments). You should use the stack for small objects as much as possible since it is faster, however if your objects are going to survive for longer than the stack frame, then it's clearly the wrong choice.
很简单,这两行都在堆栈上创建对象,而不是像“new”那样在堆上创建对象。第二行实际上涉及对复制构造函数的第二次调用,因此应避免使用(也需要按照注释中的指示进行更正)。您应该尽可能多地将堆栈用于小对象,因为它更快,但是如果您的对象的存活时间比堆栈帧长,那么这显然是错误的选择。
回答by Puppy
Ideally, a compiler would optimize the second, but it's not required. The first is the best way. However, it's pretty critical to understand the distinction between stack and heap in C++, sine you must manage your own heap memory.
理想情况下,编译器会优化第二个,但这不是必需的。第一种是最好的方法。但是,理解 C++ 中堆栈和堆之间的区别非常重要,因为您必须管理自己的堆内存。
回答by Nils
I played a bit with it and the syntax seems to get quite strange when a constructor takes no arguments. Let me give an example:
我玩了一下,当构造函数不带参数时,语法似乎变得很奇怪。让我举个例子吧:
#include <iostream>
using namespace std;
class Thing
{
public:
Thing();
};
Thing::Thing()
{
cout << "Hi" << endl;
}
int main()
{
//Thing myThing(); // Does not work
Thing myThing; // Works
}
so just writing Thing myThing w/o brackets actually calls the constructor, while Thing myThing() makes the compiler thing you want to create a function pointer or something ??!!
所以只写不带括号的 Thing myThing 实际上会调用构造函数,而 Thing myThing() 使编译器你想要创建一个函数指针之类的东西??!!
回答by bruziuz
In append to JaredParanswer
附加到JaredPar 的回答
1-usual ctor, 2nd-function-like-ctor with temporary object.
1-通常的构造函数,第二个具有临时对象的类似函数的构造函数。
Compile this source somewhere here http://melpon.org/wandbox/with different compilers
使用不同的编译器在http://melpon.org/wandbox/ 的某处编译此源代码
// turn off rvo for clang, gcc with '-fno-elide-constructors'
#include <stdio.h>
class Thing {
public:
Thing(const char*){puts(__FUNCTION__ );}
Thing(const Thing&){puts(__FUNCTION__ );}
~Thing(){puts(__FUNCTION__);}
};
int main(int /*argc*/, const char** /*argv*/) {
Thing myThing = Thing("asdf");
}
And you will see the result.
你会看到结果。
From ISO/IEC 14882 2003-10-15
来自 ISO/IEC 14882 2003-10-15
8.5, part 12
8.5,第 12 部分
Your 1st,2nd construction are called direct-initialization
您的第 1、2 次构造称为直接初始化
12.1, part 13
A functional notation type conversion (5.2.3) can be used to create new objects of its type. [Note: The syntax looks like an explicit call of the constructor. ] ... An object created in this way is unnamed. [Note: 12.2 describes the lifetime of temporary objects. ] [Note: explicit constructor calls do not yield lvalues, see 3.10. ]
12.1,第 13 部分
功能符号类型转换 (5.2.3) 可用于创建其类型的新对象。[注意:语法看起来像是对构造函数的显式调用。] ...以这种方式创建的对象是未命名的。[注:12.2 描述了临时对象的生命周期。] [注意:显式构造函数调用不会产生左值,见 3.10。]
Where to read about RVO:
在哪里阅读有关 RVO 的信息:
12 Special member functions / 12.8 Copying class objects/ Part 15
When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, evenif the copy constructor and/or destructor for the object have side effects.
12 特殊成员函数 / 12.8 复制类对象 / 第 15 部分
当满足某些条件时,允许实现省略类对象的复制构造,即使对象的复制构造函数和/或析构函数具有副作用。
Turn off it with compiler flag from comment to view such copy-behavior)
从注释中使用编译器标志将其关闭以查看此类复制行为)