C++ 将T数组别名为std::complex数组<;T>;合法的

C++ 将T数组别名为std::complex数组<;T>;合法的,c++,language-lawyer,strict-aliasing,C++,Language Lawyer,Strict Aliasing,我知道强类型别名规则。然而,他注意到 实现不能声明额外的非静态数据成员,这些成员将占用与实部和虚部不相交的存储空间,并且必须确保类模板专门化不包含任何填充。该实现还必须确保对数组访问的优化考虑到指向值类型的指针可能对std::complex专门化或其数组产生别名的可能性 这个要求是否允许像下面这样的代码是合法的,即使它不一定是道德的 std::size_t numDoubles = 100; double* a = (double*) std::malloc(numDoubles * sizeo

我知道强类型别名规则。然而,他注意到

实现不能声明额外的非静态数据成员,这些成员将占用与实部和虚部不相交的存储空间,并且必须确保类模板专门化不包含任何填充。该实现还必须确保对数组访问的优化考虑到指向值类型的指针可能对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]);
std::size\u t numDoubles=100;
double*a=(double*)std::malloc(numDoubles*sizeof(double));
std::complex*b=重新解释铸件(a);
(b[1])的剂量;
如果使用new[]生成double数组,答案是否会改变

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
//foo.h
名称空间impl{
void*分配(标准::大小\u t个字节);
}
模板
T*分配(标准::大小\u T数量){
静态断言(std::is_pod_v);
返回静态_cast(分配(num*sizeof(T));
}
//foo.cpp
#如果你在场
void*impl::Allocate(std::size_t numBytes){return LibraryAllocate(numBytes);}
#否则
void*impl::Allocate(std::size_t numBytes){return std::malloc(numBytes);}
#恩迪夫
不幸的是,std::complex不是POD,因为它有一个非常重要的默认构造函数。我希望我能忽略这个问题

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

即使您直接使用
a
而不是对复杂的
进行转换,该代码也不是严格合法的。C++对象模型不允许你只需获取一些内存,将其转换成一个类型,并假设对象存在于该内存中。无论类型如何(字节类型之外),这都是正确的

该代码从不创建
double
数组,因此您无法像访问
double
数组一样访问内存。您也不能像在那里一样访问
复合体

如果使用
new[]
生成double数组,答案是否会改变

只有在存在合法的
double
数组的意义上。那里仍然没有一个
复合体

std::complex
提供的规则是。这并不意味着您可以访问两个
T
s的任何数组,就像它是一个
std::complex

一样,因此标准部分说明如下:

// 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
如果z是cv复数类型的左值,则:

  • 重新解释(z)的表达式应格式良好
  • 重新解释(z)[0]应指定z的真实部分,以及
  • 重新解释(z)[1]应指定z的虚部
此外,如果a是cv complex*类型的表达式 表达式a[i]是为整数表达式i定义的,那么:

  • 重新解释(a)[2*i]应指定a[i]的真实部分,以及
  • 重新解释(a)[2*i+1]应指定a[i]的虚部
它不会以另一种方式为别名创建一个异常,因此看起来通过double来别名
std::complex
是无效的


使用new不会改变分析。

很公平。看来我必须在malloc'd内存中放置新的内存了,我猜是吗?@JamesPicone:好吧,这就是问题所在:你是在分配内存还是在创建对象?C++标准库分配器模型对于这些单独的任务有单独的功能: Alpult::Deale分配适合于<代码> t>代码>的内存,而分配器::CREATE//COM>在这样的存储中创建对象。除了创建对象之外,分配的内存也不多。为了解释抽象,我试图得到一个T类型的数组,通常是double或std::complex,但我用于数组的内存可能来自CUDA分配函数,该函数将它放在特殊的位置,并返回一个void*。因为我试图在.cpp文件中执行此操作,所以我没有类型信息,这使得std::allocator::allocate或其他等效项无法真正发挥作用。我认为格式化程序占用了您上面答案中
字符中的一些内容。