初始化模板类成员时出现的问题
我的代码无法编译。 代码
template <typename T>
class TemplateClass
{
const T constMember;
public:
TemplateClass()
{
constMember = T();
}
};
int main()
{
TemplateClass <int> obj;
}
下面是我收到此错误的
: error: uninitialized member 'TemplateClass
我认为构造函数用于初始化数据成员。怎么了????
My code does not compile. Below is my code
template <typename T>
class TemplateClass
{
const T constMember;
public:
TemplateClass()
{
constMember = T();
}
};
int main()
{
TemplateClass <int> obj;
}
I get this error :
error: uninitialized member 'TemplateClass<int>::constMember' with 'const' type 'const int'
I thought that constructor are used to initialize data members. What's wrong????
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您没有初始化 const 成员,您只是分配给它。
成员的初始化只能使用成员初始化列表来完成。
例如:
You are not initializing the const member, you are just assigning to it.
Initialization of members can only be done using a member initialization list.
For example:
Prasoon 已经给了您一个非常好的答案。然而,我想提出一个额外的观点,我无法将其挤进评论中:
我已经看到来自语言(Java、C#)的 C++ 新手经常犯这个错误(忽略初始化列表)。 ) 其中所有类型要么是原语,要么是引用。使用
null
默认初始化对复杂类型的引用,然后用真实对象覆盖它,这没什么大不了的。然而,在 C++ 中,类型具有值语义,除非显式选择(并实现)引用语义。将您的
T
视为初始化成本较高的类型。 (对于“昂贵”的任何定义。如果您难以想象这样的类型,请想象我们正在谈论图形卡驱动程序的代码。对于此类代码来说,几乎任何东西都是昂贵的。)因为您可以自由地访问对象构造函数的主体在执行构造函数的主体时需要已经被构造。否则,您将访问原始内存而不是有效对象。 (构造是将原始内存的 blob 转变为有效的对象。)因此,当您在构造函数主体中将某些内容分配给对象时,您正在分配给一个已经完全构造的对象。由于您没有指定构造函数,因此将使用其默认构造函数来构造该对象。这意味着该对象将首先被默认构造,只是为了在下一刻用其他东西覆盖它的默认值。
这当然是无稽之谈,这就是我们有初始化列表的原因。使用它们,我们可以向编译器指定应该使用哪些构造函数来构造基类和成员子对象。这样,可以立即创建具有正确值的对象。
此外,正如您所发现的,初始化列表是初始化某些数据成员的唯一方法,即常量对象、引用和没有可访问的默认构造函数的类型的对象。
Prasoon has already given you a very good answer. However, I'd like to make an additional point, which I couldn't manage to squeeze into a comment:
I've seen this mistake (neglect of initialization lists) done a lot by C++ novices which came from languages (Java, C#) where all types are either primitives or references. It's no big deal to default-initialize a reference to a complex type with
null
and later overwrite it with a real object. In C++, however, types have value semantic, unless reference semantic is explicitly chosen (and implemented).Think of your
T
being an expensive-to-initialize type. (For any definition of "expensive". If you have trouble imagining such a type, just imagine we're talking of the code of a graphic card driver. Almost anything is expensive for such code.) Since you can freely access the object in the constructor's body it needs to already be constructed when the constructor's body is executed. Otherwise you'd be accessing raw memory instead of a valid object. (Construction is what turns a blob of raw memory into a valid object.)So when you assign something to the object in the constructor's body, you are assigning to an already fully constructed object. Since you didn't specify a constructor, the object will be constructed using its default constructor. That means the object will first be default-constructed, just to have its default value overwritten with something else in the very next moment.
That's certainly nonsense, which is why we have initialization lists. Using them, we can specify to the compiler which constructors it should use to construct base class and member sub-objects. This way, objects are created with the right value immediately.
Also, as you have discovered, initialization lists are the only way to initialize certain data members, namely constant objects, references, and objects of types that don't have an accessible default constructor.