我什么时候必须使用初始化列表来初始化 C++班级成员?
假设我有 std::map< std::string,std::string > m_someMap
作为类 A 的私有成员变量
两个问题:(我问的唯一原因是因为我遇到了这样的代码)
这一行的目的是什么:
A::A() : m_someMap()
现在我知道这是初始化,但是你必须这样做吗? 我很困惑。
std::map<的默认值是多少std::string,std::string > m_someMap
,C# 还定义 int、double 等始终初始化为默认 0,对象初始化为 null(至少在大多数情况下) 那么C++中的规则是什么?对象是否默认初始化为 null,原语初始化为垃圾? 当然,我正在考虑实例变量。
编辑:
另外,由于大多数人指出这是一种样式选择并且不是必需的,那么:
A::A() : m_someMap(), m_someint(0), m_somebool(false)
let's say I havestd::map< std::string, std::string > m_someMap
as a private member variable of class A
Two questions: (and the only reason I'm asking is because I came across code like that)
What's the purpose of this line:
A::A() : m_someMap()
Now I know that this is intialization, but do you have to do this like that?
I'm confused.What's the default value of
std::map< std::string, std::string > m_someMap
, also C# defines that int, double, etc. is always initialized to defualt 0 and objects are to null (at least in most cases)
So what's the rule in C++?? are object initialized by defualt to null and primitives to garbage?
Of course I'm taking about instance variables.
EDIT:
also, since most people pointed out that this is a style choice and not necessary, what about:
A::A() : m_someMap(), m_someint(0), m_somebool(false)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
m_somemap
std::map< std::string, std::string >
,即该映射的有效实例,其中没有元素。m_somebool
true
或false
。布尔值是“普通的旧数据类型”,它们没有构造函数的概念。此外,C++ 语言没有为非显式初始化的布尔值指定默认值。m_someint
m_somemap
std::map< std::string, std::string >
, i.e., a valid instance of that map which has no elements in it.m_somebool
true
orfalse
if you want it to have a known value. Booleans are "plain old data types" and they do not have the concept of a constructor. Moreover, the C++ language does not specify default values for non-explicitly-initialized booleans.m_someint
没有必要实际去做。
默认构造函数会自动执行此操作。
但有时通过使其显式化,它可以充当某种文档:
C++ 中的规则是,除非显式初始化 POD 数据,否则它是未定义的,而其他类则具有自动调用的默认构造函数(即使程序员没有显式这样做)。
但这么说。考虑一下:
在这里您希望数据默认初始化。
从技术上讲,POD 没有构造函数,所以如果 T 是 int 那么你会期望它做任何事情吗?因为它是显式初始化的,所以它被设置为 0 或 POD 类型的等效值。
对于编辑:
There is no need to actually do it.
The default constructor will autmatically do it.
But somtimes by making it explicit it acts as sort of documentation:
The rule in C++ is that unless you explicitly initialise POD data it is undefined while other classes have there default constructor called automatically (even if not explicitly done so by the programmer).
But saying that. Consider this:
Here you would exepect data to be default initialized.
Technically POD do not have constructors so if T was int then would you expect it to do anything? Becuase it was explicitly initialize it is set to 0 or the equivalent for POD types.
For the edit:
正如其他人指出的:这没有必要,但或多或少是风格问题。
好处:它表明您明确想要使用默认构造函数并使您的代码更加冗长。缺点:如果您有多个 ctor,那么维护所有这些 ctor 的更改可能会很痛苦,有时您添加类成员却忘记将它们添加到 ctor 初始值设定项列表中,从而使其看起来不一致。
As others pointed out: it is not necessary but more or less a matter of style.
The upside: it shows that you explicitly want to use the default constructor and makes your code more verbose. The downside: If you have more than one ctor it can be a pain to maintain changes in all of them and sometimes you add class members and forget to add them to the ctors initializer list and make it look inconsistent.
在这种情况下,这条线是不必要的。然而,一般,这是初始化类成员的唯一正确方法。
如果您有这样的构造函数:
那么当调用
X
构造函数时,会发生以下情况:y
,我们明确表示我们希望调用以z
作为参数的构造函数。对于w
,发生的情况取决于w
的类型。如果w
是 POD 类型(也就是说,基本上是 C 兼容类型:没有继承,没有构造函数或析构函数,所有成员都是 public,并且所有成员也是 POD 类型),那么它是 < em>未初始化。它的初始值是在该内存地址发现的任何垃圾。如果w
是非 POD 类型,则调用其默认构造函数(非 POD 类型始终在构造时初始化)。w
。需要注意的重要一点是,所有构造函数都是在我们进入构造函数主体之前调用的。一旦我们进入主体,所有成员都已经被初始化。
所以我们的构造函数体可能存在两个问题。
w
属于没有默认构造函数的类型怎么办?那么这将无法编译。那么它必须在:
之后显式初始化,就像y
一样。简而言之,由于
m_someMap
是非 POD 类型,严格来说我们不需要执行: m_someMap()
。无论如何,它都会被默认构建。但如果它是 POD 类型,或者如果我们想调用默认构造函数之外的另一个构造函数,那么我们就需要这样做。This line is unnecessary in this case. However, in general, it is the only proper way to initialize class members.
If you have a constructor such as this:
then the following happens when the
X
constructor is called:y
, we explicitly say we wish to call the constructor which takes az
as its argument. Forw
, what happens depends on the type ofw
. Ifw
is a POD type (that is, basically a C-compatible type: No inheritance, no constructors or destructors, all members public, and all members are POD types as well), then it is not initialized. Its initial value is whatever garbage was found at that memory address. Ifw
is a non-POD type, then its default constructor is called (non-POD types are always initialized on construction).w
.The important thing to note is that all constructors are called before we enter the body of the constructor. Once we're in the body, all members have already been initialized.
So there are two possible problems with our constructor body.
w
is of a type that doesn't have a default constructor? Then this won't compile. Then it must be explicitly initialized after the:
, likey
is.So in short, since
m_someMap
is a non-POD type, we don't strictly speaking need to do: m_someMap()
. It would have been default constructed anyway. But if it had been a POD type, or if we had wanted to call another constructor than the default one, then we would have needed to do this.只是为了清楚发生了什么(关于你的第二个问题)
std::map< std::string,std::string > m_someMap
创建一个名为 m_someMap 的堆栈变量,并在其上调用默认构造函数。 C++ 对于所有对象的规则是:其中 T 是类型,varName 是默认构造的。
应显式分配为 NULL(或 0)——或新标准中的 nullptr。
Just to be clear about what's happening (with regards to your 2nd question)
std::map< std::string, std::string > m_someMap
creates a stack variable called m_someMap and the default constructor is called on it. The rule for C++ for all of your objects is if you go:where T is a type, varName is default constructed.
should be explicitly assigned to NULL (or 0) -- or nullptr in the new standard.
澄清默认值问题:
C++ 没有某些类型隐式引用的概念。除非某些东西被显式声明为指针,否则它不能采用空值。这意味着每个类都会有一个默认构造函数,用于在未指定构造函数参数时构建初始值。如果没有声明默认构造函数,编译器将为您生成一个。此外,每当类包含类类型的成员时,这些成员将在对象构造时通过它们自己的默认构造函数隐式初始化,除非您使用冒号语法显式调用不同的构造函数。
碰巧的是,所有 STL 容器类型的默认构造函数都会构建一个空容器。其他类可能对其默认构造函数的功能有其他约定,因此您仍然需要知道它们在这种情况下被调用。这就是为什么
A::A() : m_someMap()
行实际上只是告诉编译器执行它已经执行的操作。To clarify the default value issue:
C++ does not have the concept of some types implicity being by-reference. Unless something is explicitly declared as a pointer, it cannot ever take a null value. This means that every class will have a default constructor for building the initial value when no constructor parameters are specified. If no default constructor is declared, the compiler will generate one for you. Also, whenever a class contains members that are of classed types, those members will be implicitly initialized via their own default constructors at object construction, unless you use the colon syntax to explicitly call a different constructor.
It just so happens that the default constructor for all STL container types builds an empty container. Other classes may have other conventions for what their default constructors do, so you still want to be aware that they're being invoked in situations like this. That's why the
A::A() : m_someMap()
line, which is really just telling the compiler to do what it would do already anyway.在C++中创建一个对象时,构造函数会经历以下顺序:
还有一些比这更具体的内容,并且某些编译器允许您强制执行某些特定顺序的操作,但这是一般想法。对于每个构造函数调用,您都可以指定构造函数参数,在这种情况下,C++ 将调用指定的构造函数,或者您也可以不理会它,C++ 将尝试调用默认构造函数。默认构造函数就是不带参数的构造函数。
如果任何虚拟父类、非虚拟父类或成员变量没有默认构造函数,或者需要使用默认构造函数以外的其他内容创建,则可以将它们添加到构造函数调用列表中。因为 C++ 假定默认构造函数调用,所以将默认构造函数放入列表中和完全将其排除在外之间绝对没有区别(C++ 不会(除非在本问题范围之外的特殊情况下)创建一个对象而不调用某种构造函数)。如果一个类没有默认构造函数并且您没有提供构造函数调用,则编译器将抛出错误。
当涉及到
float
或int
等内置类型时,默认构造函数根本不执行任何操作,因此变量将具有片段中剩余内容的默认值的记忆。所有内置类型也都有一个复制构造函数,因此您可以通过将它们的初始值作为唯一参数传递给变量的构造函数来初始化它们。When you create an object in C++, the constructor goes through the following sequence:
There are a few more specifics than this, and some compilers allow you to force a few things out of this specific order, but this is the general idea. For each of these constructor calls you can specify the constructor arguments, in which case C++ will call the constructor as specified, or you can leave it alone and C++ will try to call the default constructor. The default constructor is simply the one that takes no arguments.
If any of your virtual parent classes, non-virtual parent classes, or member variables don't have a default constructor or need to be created with something other than the default, you add them to the list of constructor calls. Because C++ assumes a default constructor call, there is absolutely no difference between putting a default constructor in the list and leaving it out entirely (C++ will not (unless under special circumstances outside the scope of this question) create an object without a call to a constructor of some sort). If a class does not have a default constructor and you do not provide a constructor call, the compiler will throw an error.
When it comes to built in types such
float
orint
, the default constructor does nothing at all, and so the variable will have the default value of whatever was left in the piece of memory. All built in types also have a copy constructor so you can you can initialize them by passing their initial value as the only argument to the variable's constructor.