C++构造函数初始化列表调用默认构造函数.为什么



看看我的代码。它将把Vector4转换为Vector4。有一个复制构造函数,它自动逐个组件进行转换。我不明白一件事:为什么在构建结束时,当每个组件都正确设置时,会在每个组件上调用默认构造函数,使输出向量为空。您可以在下面的输出中看到执行流程。有趣的是,如果我用4个赋值替换初始化列表,代码就会按预期工作。

编译器是VS2013。

#include <cstdio>
using namespace std;
struct half
{
unsigned short data;
half() : data(0) { printf("half::default_constructorn"); }
half(half& pattern) : data(pattern.data) { printf("half::copy_constructorn"); }
explicit half(float pattern) : data(16) { printf("half::from_float_constructorn"); }
operator float() { printf("half::to_float_operatorn"); return 3.0f; }
};
template <typename T>
struct Vector4
{
Vector4() : x(0), y(0), z(0), w(0) { }
Vector4(T value) : x(value), y(value), z(value), w(value) { }
Vector4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) { }
template <typename U>
Vector4(Vector4<U>& other) : x((T)other.x), y((T)other.y), z((T)other.z), w((T)other.w) { }
union
{
struct { T x, y, z, w; };
struct { T r, g, b, a; };
};
};
int main()
{
Vector4<float> a(0, 1, 4, 6);
Vector4<half> b(a);
}

该程序的输出:

half::from_float_constructor
half::to_float_operator
half::from_float_constructor
half::from_float_constructor
half::to_float_operator
half::from_float_constructor
half::from_float_constructor
half::to_float_operator
half::from_float_constructor
half::from_float_constructor
half::to_float_operator
half::from_float_constructor
half::default_constructor
half::default_constructor
half::default_constructor
half::default_constructor

原因是代码无效。不能将非POD类型存储在联合中。您的代码会导致未定义的行为。我不知道编译器到底做了什么,也不知道它为什么调用默认构造函数1——但这对你来说是未定义的行为。


1尽管我有一个理论:它可能试图初始化rgba

首先,C++没有匿名结构。因此,Vector4成员的定义

union
{
struct { T x, y, z, w; };
struct { T r, g, b, a; };
};

不符合C++。我认为您使用的是具有此类语言扩展的MS VC++

现在让我们考虑一下发生了什么。

在模板构造函数的mem初始值设定项列表中

template <typename U>
Vector4(Vector4<U>& other) : x((T)other.x), y((T)other.y), z((T)other.z), w((T)other.w) { }

(T)other.x为例的C样式转换调用类half的构造函数

explicit half(float pattern) : data(16) { printf("half::from_float_constructorn"); 

此调用的结果是创建一个类型为half的临时对象

不能应用类half的复制构造函数,因为它的参数被声明为非常量引用,并且临时对象不能绑定到非常量引用。

half(half& pattern) : data(pattern.data) { printf("half::copy_constructorn"); }

因此构造函数会搜索其他路径来完成任务。

它可以将临时对象转换为float 类型的对象

operator float() { printf("half::to_float_operatorn"); return 3.0f; }
};

最后调用构造函数

explicit half(float pattern) : data(16) { printf("half::from_float_constructorn"); }

因此,您可以得到以下消息序列

half::from_float_constructor
half::to_float_operator
half::from_float_constructor

我准备了一个更简单的C++兼容示例,演示了相同的行为

#include <iostream>
struct A
{
float x = 0.0f;
};
struct B
{
explicit B( float ){ std::cout << "B::from_float_constructor" << std::endl; }
B( B & ){ std::cout << "B::from_copy_constructor" << std::endl; }
operator float () const 
{ 
std::cout << "B::to_float_operator" << std::endl; 
return 0.0f;
}
};
struct C
{
B b;
C( A a ) : b( ( B )a.x ) {}
};
int main() 
{
A a;
C c( a );
return 0;
}

输出为

B::from_float_constructor
B::to_float_operator
B::from_float_constructor

相关内容

  • 没有找到相关文章

最新更新