假设我们有一个指针T* ptr;
和ptr, ptr+1, … ptr+(n-1)
都引用了类型为T的有效对象。
是否可以像访问STL array
那样访问它们?或者执行以下代码:
std::array<T,n>* ay = (std::array<T,n>*) ptr
调用未定义的行为?
答案 0 :(得分:3)
是的,它是一个未定义的行为,一个经典的行为......
首先,要了解你刚刚做了什么:
std::array<T,n>* ay = (std::array<T,n>*) ptr
可翻译为:
using Arr = std::array<T,n>;
std::array<T,n>* ay = reinterpret_cast<Arr*>( const_cast<TypeOfPtr>(ptr));
您不仅可以获得所有const
和volatile
资格,还可以投放该类型。看到这个答案:https://stackoverflow.com/a/103868/1621391 ...不分青红皂白地抛弃cv
资格也可以导致UB。
其次,通过从不相关类型转换的指针访问对象是未定义的行为。见the strict aliasing rule(谢谢天顶)。因此,通过指针ay
的任何读或写访问都是未定义的。如果你非常幸运,代码应该立即崩溃。如果它奏效了,邪恶的日子正等着你......
请注意,std::array
不会,也不会与非std::array
的任何内容相同。
只需添加...在working draft of the C++ standard中,它会列出out explicit conversion rules。 (你可以阅读)并有一个陈述
的条款.....
5.4.3:以下未提及且未明确定义的任何类型转换 用户([class.conv])格式不正确。
.....
我建议你自己做饭array_view
(希望能用C ++ 17编写)。它真的很容易。或者,如果你想要一些所有权,你可以做一个这样简单的:
template<typename T>
class OwnedArray{
T* data_ = nullptr;
std::size_t sz = 0;
OwnedArray(T* ptr, std::size_t len) : data_(ptr), sz(len) {}
public:
static OwnedArray own_from(T* ptr, std::size_t len)
{ return OwnedArray(ptr, len); }
OwnedArray(){}
OwnedArray(OwnedArray&& o)
{ data_ = o.data_; sz = o.sz; o.data_=nullptr; o.sz=0; }
OwnedArray& operator = (OwnedArray&& o)
{ delete[] data_; data_ = o.data_; sz = o.sz; o.data_=nullptr; o.sz=0; }
OwnedArray(const OwnedArray& o) = delete;
OwnedArray& operator = (const OwnedArray& o) = delete;
~OwnedArray(){ delete[] data_; }
std::size_t size() const { return sz; }
T* data() return { data_; }
T& operator[] (std::size_t idx) { return data_[idx]; }
};
...您可以根据需要推出更多成员函数/ const资格。但这有警告......指针必须已经通过new T[len]
因此,你可以在你的例子中使用它:
auto ay = OwnedArray<decltype(*ptr)>::own_from(ptr, ptr_len);
答案 1 :(得分:2)
是的,这会调用未定义的行为。通常,您无法在彼此之间转换指向不相关类型的指针。
代码与
没有什么不同std::string str;
std::array<double,10>* arr = (std::array<double,10>*)(&str);
说明:标准不对std::array<T,n>
和T*
之间的任何兼容性提供任何保证。它根本就不存在。它并没有说std::array
也是微不足道的类型。如果没有这样的保证,T*
和std::array<T,n>
之间的任何转换都是未定义的行为,其大小与指向任何不相关类型的指针之间的转换相同。
我也没有看到将已构造的动态数组作为std::array
访问有什么好处。
P.S。通常的免责声明。对它自己来说,总是100%罚款。它是导致烟花爆发的结果指针的间接 - 但这部分省略了简单。
答案 2 :(得分:0)
我在这里回答第一个问题,因为第二个问题已经在其他答案中得到了处理:
回顾:你......
指针
T* ptr;
和ptr, ptr+1, … ptr+(n-1)
都引用T类型的有效对象。
你问是不是......
可以像访问STL
array
一样访问它们吗?
答:这没问题 - 但它的工作方式与您在代码示例中估算的不同:
std::array<T*, N> arr;
for(int i = 0; i<N; ++i)
{
arr[i] = ptr + i;
}
现在您可以像使用原始指针一样使用数组元素。并且在任何地方都没有未定义的行为。