将T数组别名为std :: complex <t>数组合法吗?

时间:2018-10-18 04:46:44

标签: c++ language-lawyer strict-aliasing

我知道很强的类型别名规则。但是,cppreference指出

  

实现不能声明其他非静态数据成员,这些成员将占用与实部和虚部不相交的存储,并且必须确保类模板专门化不包含任何填充。该实现还必须确保对数组访问的优化考虑了指向value_type的指针可能会将std :: complex特化或其数组作为别名的可能性。

此要求是否允许如下代码是合法的,即使它不一定是道德的?

std::size_t numDoubles = 100;
double* a = (double*) std::malloc(numDoubles * sizeof(double));
std::complex<double>* b = reinterpret_cast<std::complex<double>*>(a);
DoSomethingWith(b[1]);

如果使用new []生成双精度数组,答案会改变吗?

XY问题解释:我试图抽象一个可能不存在的第三方库提供的分配器。分配器返回void *;我正在尝试避免将确实存在的库详细信息泄漏到标头中。所以我的结构如下:

// foo.h
namespace impl {
    void* Allocate(std::size_t numBytes);
}

template<typename T>
T* Allocate(std::size_t num) {
    static_assert(std::is_pod_v<T>);
    return static_cast<T*>(Allocate(num * sizeof(T)));
}


// foo.cpp
#if LIBRARY_PRESENT

void* impl::Allocate(std::size_t numBytes) { return LibraryAllocate(numBytes); }

#else

void* impl::Allocate(std::size_t numBytes) { return std::malloc(numBytes); }

#endif

不幸的是,std :: complex不是POD,因为它具有非平凡的默认构造函数。我希望我可以忽略这个问题。

2 个答案:

答案 0 :(得分:1)

  

此要求是否允许以下​​代码合法

即使您直接使用a而不是强制转换为complex,该代码也不是严格合法的。 C ++对象模型不允许您仅获取一些内存,将其转换为类型,并假装对象存在于该内存中。无论类型如何(字节类型之外)都是如此。

该代码永远不会创建double数组,因此您无法像访问double数组那样访问内存。您也无法像访问complex<double>一样访问它。

  

如果使用new[]来生成双精度数组,答案会改变吗?

仅在某种意义上将存在double的合法数组。那里还没有complex<double>

std::complex<T>提供的规则是you can access its members as though it were an array of two Ts。这不是不是,意味着您可以访问两个T的任何数组,就好像它是std::complex<T>

答案 1 :(得分:1)

因此,标准部分[complex.numbers]p4表示以下内容:

  

如果z是cv complex类型的左值,则:

     
      
  • 表达式reinterpret_­cast(z)应该格式正确,
  •   
  • reinterpret_­cast(z)[0]应指定z的实部,并且
  •   
  • reinterpret_­cast(z)[1]应指定z的虚部。
  •   
     

此外,如果a是cv complex *类型的表达式,并且   对于整数表达式i,表达式a [i]定义明确,然后:

     
      
  • reinterpret_­cast(a)[2 * i]应指定a [i]的实部,并且
  •   
  • reinterpret_­cast(a)[2 * i +1]应指定a [i]的虚部。
  •   

相反,它不会为strict aliasing rule排除异常,因此通过 double 别名std::complex<double>似乎无效。

使用new不会更改分析。