在对我的程序进行概要分析时,我意识到使用std::complex<double>()
将10%的代码花在了一个愚蠢的new std::complex<double>[size_of_array]
构造函数中。
我在网上搜索过,std::complex
的默认构造函数似乎将值double()视为实部和虚部。由于C ++没有初始化双数,我想知道为什么g ++很难用零来初始化std::complex
,以及我是否可以通过某种方式解决整个程序(*)
(*)现在我必须特殊情况下创建复数数组的函数来分配未初始化的双精度数组并将它们重新组合为复数。
编辑:如下所示,这是对我的疏忽。默认构造函数具有实部和虚部(http://en.cppreference.com/w/cpp/numeric/complex/complex)
的空构造函数 complex( const T& re = T(), const T& im = T() );
但规范然后介绍了双重
的特殊情况 complex(double re = 0.0, double im = 0.0);
正是这种特殊情况引入了所有开销,因为它绕过了&#39; double&#39;的实际默认构造函数。什么都不做(与int,long,float等相同)。
答案 0 :(得分:5)
我想知道为什么g ++很难用zeros初始化std :: complex
因为标准说必须这样做,所以默认构造函数声明为:
constexpr complex(double re = 0.0, double im = 0.0);
所以它将两个成员都设置为零。
标准库安全地初始化类型是正常的,而不是像使用内置类型(例如double
和int*
那样使它们保持未初始化,例如std::vector<double>
为零 - 如果你调整它的大小,它也会初始化它的元素,以便添加新的元素。您可以通过不向vector
添加元素来控制vector
的此内容,直到您知道您希望它们具有哪些值为止。
complex
的一种可能解决方法是使用不进行初始化的类型:
struct D
{
D() noexcept { }; // does not initialize val!
D(double d) noexcept : val(d) { }
operator double() const noexcept { return val; }
D& operator=(double d) noexcept { val = d; return *this; }
double val;
};
现在,如果您使用std::complex<D>
,则默认构造函数不执行任何操作。将explicit
添加到转换构造函数和/或转换运算符以符合您的口味。
答案 1 :(得分:4)
有一种简单的方法。如果你使用std :: vector“保留”内存的速度要快得多,因为它不会在每个元素上调用构造函数。
即:
std::vector< std::complex< double > > vec;
vec.reserve( 256 );
for( int i = 0; i < 256; i++ )
{
vec.push_back( std::complex< double >( 1, 1 ) );
}
将明显快于此:
std::complex< double >* arr = new std::complex< double >[256];
for( int i = 0; i < 256; i++ )
{
arr[i]( std::complex< double >( 1, 1 ) );
}
delete[] arr;
因为构造函数仅在第一个示例中被调用一次。
它还有一个额外的好处就是你有RAII,而且当'vec'超出范围时会自动释放。
答案 2 :(得分:0)
以下是我正在开发的代码。
稍后补充:作为M.M.在评论中指出,行为在技术上是未定义的。现在我看到,如果一些狡猾的黄鼠狼改变了std :: complex的实现,以致它不能轻易地构建/破坏,那么这将成为一个裁剪者。另请参阅http://en.cppreference.com/w/cpp/types/aligned_storage上的示例。
#include <complex>
#include <type_traits>
typedef std::complex<double> complex;
// Static array of complex that does not initialize
// with zeros (or anything).
template<unsigned N>
struct carray {
typedef
std::aligned_storage<sizeof(complex), alignof(complex)>::type raw;
raw val[N];
complex& operator[] (unsigned idx) {
return reinterpret_cast<complex&> (val[idx]);
}
complex* begin() { return &operator[](0); }
complex* end() { return &operator[](N); }
};