我知道很强的类型别名规则。但是,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,因为它具有非平凡的默认构造函数。我希望我可以忽略这个问题。
答案 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 T
s。这不是不是,意味着您可以访问两个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不会更改分析。