在C++中使用memset清空一个pair数组

3

我有一个成对的数组。我想使用memset函数将该数组中的元素设置为0、1或-1。如何做到呢?这是我们通常所做的正常程序吗?

该数组的格式为:

std::pair<int, int> ar[100][100];

8
在C++中,几乎不需要使用memset。只需使用初始化器即可。 - Cody Gray
你有一个数组的数组对。那么你想要memset整个东西,还是只有一个数组对? - juanchopanza
4
你要如何把这个 memset 成为 1,“就像我们一般做的那样”? - melpomene
1
如果您打印“ar”的内容,无论是键还是值,都应该为0,不需要将其初始化为0。 - Asesh
默认情况下,每对成员都将被初始化为零。 - juanchopanza
如果我想设置为-1怎么办?尽管我使用了一个布尔数组来指示特定索引是否已初始化。@juanchopanza - Misbah Ahmad
3个回答

6
不要对任何不是 POD 类型的东西使用 memsetstd::pair 就不是),这样做会导致未定义行为。
带有构造函数的类需要调用这些构造函数,memset 不会这样做。具有非 POD 数据成员的类需要调用这些成员的构造函数,memset 无法做到这一点。
对于小数组,可以使用 聚合初始化。对于更大的数组,可以使用循环。还有 std::fill
我还建议在编译时已知大小时使用 std::array 而不是 C 风格的数组,否则使用 std::vector

1
std::pair甚至不是一种类型。但是了解在std::pair<int,int>上使用memset具体存在什么问题会很有趣。 - juanchopanza
@juanchopanza - 引用自http://en.cppreference.com/w/cpp/string/byte/memset "如果对象不是平凡可复制 (例如,标量、数组或 C 兼容结构体),则行为未定义。"而std::pair不是平凡可复制的。 - Jesper Juhl

1
正如提到的那样,一对并不是POD。
然而,数据可以重组为POD,且几乎不损失效用:
#include <tuple>
#include <utility>
#include <cstring>

/* this is a POD */
using pair_matrix = int [100][100][2];

extern std::tuple<int, int> foo();
extern void bar(std::tuple<int&, int&>);

int main()
{
    pair_matrix m;

    /* we can memset PODS */
    std::memset(std::addressof(m), sizeof(m), 0);

    /* we can convert the 2-d array into a tuple easily */
    auto at = [&m](int x, int y) {
        auto& a = m[y][x];
        return std::tie(a[0], a[1]);
    };

    /* and manipulate as a tuple */
    at(10,10) = foo();
    bar(at(10,10));
}

另一种(可能更健壮的)方法是发明一个多维数组类的概念,该类具有fill方法:
#include <tuple>
#include <utility>
#include <memory>

template<class Type, std::size_t...Dimensions> struct dimension_view;
template<class Type> struct dimension_view<Type>
{
    static constexpr std::size_t extent = 1;
    static constexpr std::size_t size() { return extent; }
    static constexpr std::size_t storage_size = 1;

    using storage_type = Type;

    constexpr dimension_view(Type* data) : data_(data) {}

    operator Type&() { return *data_; }

    template<class Other>
    constexpr Type& operator=(Other&& other) {
        *data_ = std::forward<Other>(other);
        return *data_;
    }

    storage_type* data_;
};

template<class Type, std::size_t Dim, std::size_t...Rest> 
struct dimension_view<Type, Dim, Rest...>
{
    using next = dimension_view<Type, Rest...>;
    static constexpr std::size_t extent = Dim;
    static constexpr std::size_t size() { return extent; }
    static constexpr std::size_t storage_size = Dim * next::storage_size;

    using storage_type = Type [storage_size];

    constexpr dimension_view(Type* data) : data_(data) {}

    auto begin() -> Type*
    {
        return data_;
    }
    auto end() -> Type*
    {
        return std::addressof(data_[extent * next::storage_size]);
    }

    auto operator[](std::size_t i) {
        return next(std::addressof(data_[i * next::storage_size]));
    }

    Type* data_ ;
};

template<class T, std::size_t...Dims>
struct multi_dimensional_array
{
    using view_type = dimension_view<T, Dims...>;
    using storage_type = typename view_type::storage_type;

    template<class...Args, std::enable_if_t<std::is_nothrow_constructible<T, Args...>::value>* = nullptr>
    constexpr multi_dimensional_array(Args&&...args)
    {
        for(auto&& store : data_)
        {
            new (std::addressof(store)) T (args...); 
        }
    }

    template<class...Args, std::enable_if_t<not std::is_nothrow_constructible<T, Args...>::value>* = nullptr>
    multi_dimensional_array(Args&&...args)
    {
        auto count = std::size_t(0);
        try {
            for(auto&& store : data_)
            {
                new (std::addressof(store)) T (args...); 
                ++count;
            }
        }
        catch(...) {
            destroy(count);
        }
    }

    /* delete copies for now */
    multi_dimensional_array(multi_dimensional_array const&) = delete;
    multi_dimensional_array& operator=(multi_dimensional_array const&) = delete;
    multi_dimensional_array(multi_dimensional_array &&) = delete;
    multi_dimensional_array& operator=(multi_dimensional_array &&) = delete;

    ~multi_dimensional_array()
    {
        destroy(view_type::storage_size);
    }

    void destroy(std::size_t last)
    {
        while(last--) {
            reinterpret_cast<T*>(get_data()+last)->~T();        }
    }

    constexpr auto begin_storage() { 
        return view_type(get_data()).begin();
    }

    constexpr auto end_storage() { 
        return view_type(get_data()).end();
    }

    constexpr auto fill(T value) -> void
    {
        std::fill(begin_storage(), end_storage(), value);
    }

    constexpr auto operator[](std::size_t i) -> decltype(auto) {
        return view_type(get_data())[i];
    }

    constexpr T* get_data() {
        return reinterpret_cast<T*>(data_);
    }

    std::aligned_storage_t<sizeof(T), alignof(T)> data_[view_type::storage_size];
};

using pair_matrix = multi_dimensional_array<std::pair<int, int>, 100, 100>;


void force_view(pair_matrix&);
void force_deref(std::pair<int, int>&);
std::size_t getval();

int main()
{
    /* create with initial values */
    pair_matrix m(std::make_pair(-1, 1));

    /* fill the entire multidimentional array */
    m.fill(std::make_pair(-1, -1));

    m[10][10] = std::make_pair(1,1);

    /* force compiler to generate some code to exercise implementation */
    force_view(m);
    force_deref(m[getval()][getval()]);
}

1

C++的做法是使用std::fill而不是memset,类似于:

std::pair<int, int> ar[100][100];
std::fill(&ar[0][0], &ar[0][0] + 100 * 100, std::make_pair(-1, -1));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接