我对这个 C++ 构造函数感到困惑
I'm confused about this C++ constructor
我尝试寻找答案,但不确定用于描述此问题的最佳术语...
我正在阅读一本关于 SFML 编程的书,其中一个例子让我对构造函数的用法感到困惑。
假设我们有 class A 和 class B。Class A 有一个类型 B (memberB) 的成员变量。 A 的构造函数如下所示:
A::A() : OtherMemberType(with, params), memberB()
{...}
鉴于memberB 正在使用初始化列表中的默认构造函数进行初始化,将其明确列在列表中的目的是什么?不把它列入清单,岂不是一样的效果?
谢谢
编辑:感谢您的回答。我现在已经了解了值初始化与默认初始化的(基本)区别。
有关更多上下文,由于 "class B may be broken was brought up" 的想法,这里是文本 SFML Game Development 中的代码示例:
class Game
{
public:Game();
void run();
private:
void processEvents();
void update();
void render();
private:
sf::RenderWindow mWindow;
sf::CircleShape mPlayer;
};
Game::Game()
: mWindow(sf::VideoMode(640, 480), "SFML Application")
, mPlayer()
{
mPlayer.setRadius(40.f);
mPlayer.setPosition(100.f, 100.f);
mPlayer.setFillColor(sf::Color::Cyan);
}
那么在这种情况下,有人知道 SFML 的一些细节吗?是sf::CircleShape"broken",还是这是对默认构造函数的冗余调用?
亚当
正在初始化初始化列表中的成员value-initializes it. Omitting it from the list default-initializes它,
如果B
是非聚合并且有默认构造函数,则没有区别。
如果B
是一个集合,那么可能会有差异。 default-initializing 这意味着如果它包含内置函数,这些可能不会被初始化。 值初始化它最终会产生对其成员进行零初始化的效果。
这是一个初始化语义不同的示例:
struct B
{
int i, j, k;
};
struct A
{
A() : b() {} // value-initializes b: b.i, b.j, b.k zero initialized
B b;
};
struct AA
{
AA() {} // default-initializes b: b.i, b.j, b.k have no initialization
B b;
};
通过将其包含在初始化列表中,该成员被值初始化。如果不是,它将是默认初始化。是否有差异取决于类型。
如果它是具有已声明的默认构造函数的 class 类型,则没有区别:在任何一种情况下都将使用该构造函数。
否则,值初始化将零初始化原始类型(和 class 类型的原始成员),而在某些情况下,默认初始化将使它们保持未初始化状态,并具有不确定的值。
更新: 在您的特定情况下,class 确实有一个 default constructor,因此显式初始化是多余的。但冗余不一定是坏事 - 它表明它被故意值初始化,而不仅仅是被遗忘。
鉴于 mike 和 juan 所说的,我认为 class B
的实现是错误的,前提是它需要像那样进行值初始化 除非 可以合理地预期会那样做。
一般来说,给定一个正确设计的 class - 使用用户提供的默认构造函数 iff 如果有 POD 成员 - 值初始化和默认初始化类型 B 的成员之间的行为应该没有区别。
一些特殊的 classes 可能不会对其成员执行零初始化,并且它们可能缺少默认构造函数。 std::array
就是这样一个 class。他们试图保留作为其实现基础的原始类型的性能。此类 classes 的成员将需要值初始化。
有几种可能:
Class B
是具有通常行为的值初始化是多余的。具体来说:
a) class B
没有POD类型的成员,非POD类型的成员类型都按照可能性#1实现,或者
b) class B
的用户编写的默认构造函数会根据需要初始化所有 POD 类型的成员。
Class B
具有性能优化类型的语义,例如数值类型或原始 C 数组的替代。它缺少默认构造函数,除非您执行值初始化,否则不会初始化。示例:std::array<T>
其中 T
是 POD。
Class B
是模板参数。在 B
没有任何约束的情况下,值初始化是唯一安全的选择。毕竟 B
可能是 std::array
。
Class B
坏了。如果它的实例是值初始化的,它的成员将被正确初始化。需要修复。
我尝试寻找答案,但不确定用于描述此问题的最佳术语...
我正在阅读一本关于 SFML 编程的书,其中一个例子让我对构造函数的用法感到困惑。
假设我们有 class A 和 class B。Class A 有一个类型 B (memberB) 的成员变量。 A 的构造函数如下所示:
A::A() : OtherMemberType(with, params), memberB()
{...}
鉴于memberB 正在使用初始化列表中的默认构造函数进行初始化,将其明确列在列表中的目的是什么?不把它列入清单,岂不是一样的效果?
谢谢
编辑:感谢您的回答。我现在已经了解了值初始化与默认初始化的(基本)区别。
有关更多上下文,由于 "class B may be broken was brought up" 的想法,这里是文本 SFML Game Development 中的代码示例:
class Game
{
public:Game();
void run();
private:
void processEvents();
void update();
void render();
private:
sf::RenderWindow mWindow;
sf::CircleShape mPlayer;
};
Game::Game()
: mWindow(sf::VideoMode(640, 480), "SFML Application")
, mPlayer()
{
mPlayer.setRadius(40.f);
mPlayer.setPosition(100.f, 100.f);
mPlayer.setFillColor(sf::Color::Cyan);
}
那么在这种情况下,有人知道 SFML 的一些细节吗?是sf::CircleShape"broken",还是这是对默认构造函数的冗余调用?
亚当
正在初始化初始化列表中的成员value-initializes it. Omitting it from the list default-initializes它,
如果B
是非聚合并且有默认构造函数,则没有区别。
如果B
是一个集合,那么可能会有差异。 default-initializing 这意味着如果它包含内置函数,这些可能不会被初始化。 值初始化它最终会产生对其成员进行零初始化的效果。
这是一个初始化语义不同的示例:
struct B
{
int i, j, k;
};
struct A
{
A() : b() {} // value-initializes b: b.i, b.j, b.k zero initialized
B b;
};
struct AA
{
AA() {} // default-initializes b: b.i, b.j, b.k have no initialization
B b;
};
通过将其包含在初始化列表中,该成员被值初始化。如果不是,它将是默认初始化。是否有差异取决于类型。
如果它是具有已声明的默认构造函数的 class 类型,则没有区别:在任何一种情况下都将使用该构造函数。
否则,值初始化将零初始化原始类型(和 class 类型的原始成员),而在某些情况下,默认初始化将使它们保持未初始化状态,并具有不确定的值。
更新: 在您的特定情况下,class 确实有一个 default constructor,因此显式初始化是多余的。但冗余不一定是坏事 - 它表明它被故意值初始化,而不仅仅是被遗忘。
鉴于 mike 和 juan 所说的,我认为 class B
的实现是错误的,前提是它需要像那样进行值初始化 除非 可以合理地预期会那样做。
一般来说,给定一个正确设计的 class - 使用用户提供的默认构造函数 iff 如果有 POD 成员 - 值初始化和默认初始化类型 B 的成员之间的行为应该没有区别。
一些特殊的 classes 可能不会对其成员执行零初始化,并且它们可能缺少默认构造函数。 std::array
就是这样一个 class。他们试图保留作为其实现基础的原始类型的性能。此类 classes 的成员将需要值初始化。
有几种可能:
Class
B
是具有通常行为的值初始化是多余的。具体来说:a) class
B
没有POD类型的成员,非POD类型的成员类型都按照可能性#1实现,或者b) class
B
的用户编写的默认构造函数会根据需要初始化所有 POD 类型的成员。Class
B
具有性能优化类型的语义,例如数值类型或原始 C 数组的替代。它缺少默认构造函数,除非您执行值初始化,否则不会初始化。示例:std::array<T>
其中T
是 POD。Class
B
是模板参数。在B
没有任何约束的情况下,值初始化是唯一安全的选择。毕竟B
可能是std::array
。Class
B
坏了。如果它的实例是值初始化的,它的成员将被正确初始化。需要修复。