5

这是未定义的行为吗?

std::array<int, 5> x = {3, 5, 1, 2, 3};
std::array<int, 3>& y = *reinterpret_cast<std::array<int, 3>*>(&x[1]);
for(int i = 0; i != 3; i++) {
    std::cout << y[i] << "\n";
}

也许是的,但我真的觉得应该有一种安全的方式来切片std::arrays。

编辑:遵循 Radek 的建议:

template<unsigned N, unsigned start, unsigned end, typename T>
std::array<T, end - start>& array_slice(std::array<T, N>& x)
{
    static_assert(start <= end, "start <= end");
    static_assert(end <= N-1, "end <= N");
    return *reinterpret_cast<std::array<T, end - start>*>(&x[start]);
}

编辑:好的,我决定我对std::arrays 不满意,会转向别的东西,有什么想法吗?

4

2 回答 2

6

是的,这是未定义的行为。您正在采用一种类型并将reinterpret_cast其转换为另一种类型。确实,使用reinterpret_cast应该是“这里有龙!”的大红旗!

至于切片数组,这不会发生。Astd::array包含值;其中的一部分将包含对该数组的一部分的引用。因此,它不会是std::array. 您可以复制数组切片,但不能使用std::array. 您需要使用std::vector,因为它允许调用构造函数,以及从一系列值进行构造。请记住:std::array它只是 C 样式数组的一个更好的包装器。

委员会正在研究一个模板array_ref<T>类,这正是它所说的:对类型数组的某些段的引用T。这可以是一个常规的 C 风格的数组, a std::vector, a std::array,或者只是一些用 分配的内存new T[]。已经有一些类的库实现,但还没有标准化。


遵循 Radek 的建议:

在函数中隐藏未定义的行为不会使其成为已定义的行为。你可以试着假装它不是未定义的,但它仍然是。在你使用它的那一刻reinterpret_cast,你心甘情愿地放弃生活在 C++ 领域。

于 2012-05-25T20:12:29.663 回答
-1

新的展示位置怎么样?

#include <array>
#include <iostream>
#include <iterator>

template<typename T, std::size_t N>
struct array_slice : public std::array<T,N> {
    ~array_slice() = delete; 
};

int main() {
    std::array<double,4> x_mu{0.,3.14,-1.,1.};
    std:: cout << &x_mu << std::endl;

    {
        auto slicer = [] (std::array<double,4>& ref) {
            array_slice<double,3>* p = new (&ref) array_slice<double,3>;
            return p;
        };    

        std::array<double,3>& x_  = *slicer(x_mu);
        std::copy(x_.begin(),x_.end(),
              std::ostream_iterator<float>(std::cout," "));
        std:: cout << std::endl;
        std:: cout << &x_ << std::endl;
    }

    std::copy(x_mu.begin(),x_mu.end(),
              std::ostream_iterator<float>(std::cout," "));
}
于 2014-07-06T15:53:28.790 回答