假设我们有一个指针 T* ptr;
和 ptr, ptr+1, … ptr+(n-1)
都引用有效的 T 类型对象。
是否可以像访问 STL array
一样访问它们?或者执行以下代码:
std::array<T,n>* ay = (std::array<T,n>*) ptr
调用未定义的行为?
最佳答案
是的,它是一个未定义的行为,一个经典的...
首先,了解你刚刚做了什么:
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: Any type conversion not mentioned below and not explicitly defined by the user ([class.conv]) is ill-formed.
.....
我建议你自己做饭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);
关于c++ - std::array 可以别名更大数组的片段吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36508995/