簡體   English   中英

在 C++ 的結構中初始化 static arrays 的最佳策略

[英]Best strategy for initializing static arrays in a struct in C++

假設該結構提供了兩個模板 arguments,一個是typename T ,另一個是size_t N 現在,該結構應該存儲元素類型T和大小N的 static 數組。 在某些情況下,在創建實例時使用默認值初始化數組可能會很好,如果你有類似的東西,我認為無論如何都會發生這種情況

template<typename T, size_t N>
struct Foo {
    T values[N];
    size_t size;
    
    explicit Foo(size_t _size) : size{ _size } {}
}

因此,如前所述,我認為這種情況下的行為是values會自動使用默認值初始化(調用T的默認構造函數)。 但是,如果我想在構造 object 時為數組傳遞一些值怎么辦? 這里的目標是我能夠將 static 數組傳遞給構造函數,並讓 static 數組代替values 理想情況下,整個過程中只有兩個數組創建。 但這可能嗎? 考慮以下示例:

template<typename T, size_t N>
struct Foo {
    T values[N];
    size_t size;
    
    explicit Foo(T _values[N], size_t _size) : values{ _values }, size{ _size} {}
}

現在,除了我什至不知道上述是否會按預期工作之外,我仍然有點不確定 C++ 何時發生副本。 我想在最壞的情況下,調用Foo的構造函數時會創建 4 個 arrays :

  1. 要調用Foo的構造函數,您需要傳遞一個數組,因此您需要事先創建它。
  2. 構造函數參數_values是按值傳遞的,所以這里發生了一個副本。
  3. 在構造函數初始化任何值之前,static 數組已經初始化(?)
  4. _values分配給values時,正在發生另一個副本(?)

現在正如所說,我真的不確定 C++ 中的復制行為。 當然,我們可以通過使_values參數按引用傳遞來排除創建一個數組的可能性。 但是,static 數組values仍然會在被_values覆蓋之前被初始化,或者我認為

因此,我的問題是:這里最好的策略是什么? 我如何編寫代碼才能觸發最少的數組創建?

謝謝!

編輯:

不,我不能使用std::vector或 stdlib 中的任何其他數據結構。 即使可以,我的問題仍然是關於原始 arrays的最佳策略,而不是如何切換我的方法以支持某些包裝器。

為了避免復制和指針衰減, _values可以通過引用傳遞:

template<typename T, std::size_t N>
struct Foo {
    T values[N];
    std::size_t size;
    
    explicit Foo(T const(&_values)[N], std::size_t _size) : size{ _size}{
         std::copy(std::begin(_values), std::end(_values), std::begin(values));
    }
};

https://godbolt.org/z/dnb9zTooG

但最好使用std::array<T, N> values; 成員。


這個答案引起了一些爭議。 需要明確的是,如果問題是嵌套數組的初始化,最好不要(任何)構造函數並使用聚合初始化。 如果您想用 class 做其他事情,這是非常有限的。 最后,無論如何您都在重新發明std::array

你可以這樣做:

#include <cstddef>
#include <type_traits>
#include <utility>
#include <algorithm>

using namespace std;

struct S
{
    S();
    S(int);
    S(S const&);
    S(S&&);
    ~S();
    S& operator=(S const&);
    S& operator=(S&&);
};


template<class F>
struct inplacer
{
    F f_;
    operator std::invoke_result_t<F&>() { return f_(); }
};

template<class F> inplacer(F) -> inplacer<F>;


template<size_t maxN, typename T>
struct myarray
{
    size_t      sz_{};
    T           data_[maxN];
    
    template<class... Ts>
    myarray(Ts&&... args) : sz_{sizeof...(Ts)}, data_{forward<Ts>(args)...} {}

    template<class E, size_t N>
    static myarray make(E const (&a)[N], size_t count = N)
    {
        return make_copy(a, count, make_index_sequence<maxN>());
    }

    template<class E, size_t N>
    static myarray make(E (&&a)[N], size_t count = N)
    {
        return make_move(a, count, make_index_sequence<maxN>());
    }

private:
    template<class E, size_t... Indices>
    static myarray make_copy(E const* p, size_t count, index_sequence<Indices...>)
    {
        auto r = myarray( inplacer{ [&]{ return Indices < count ? p[Indices] : T(); } }... );
        r.sz_ = min(count, maxN);
        return r;
    }

    template<class E, size_t... Indices>
    static myarray make_move(E* p, size_t count, index_sequence<Indices...>)
    {
        auto r = myarray( inplacer{ [&]{ return Indices < count ? move(p[Indices]) : T(); } }... );
        r.sz_ = min(count, maxN);
        return r;
    }
};


auto f()
{
    auto v = myarray<16, int>(1, 2);

    //myarray<100, int> v = {3, 4};

    //static int d[] = {1, 2, 3, 4};
    //auto v = myarray<12, int>::make(d, 3);

    //myarray<4, S> v = {S(1), 2};
    //myarray<4, S> v = {inplacer{ []{ return S(1); } }, 2};

    //static S d[] = {3, 4, 1};
    //auto v = myarray<4, S>::make(d, 2);
    //auto v = myarray<4, S>::make(move(d));

    return v;
}

我敢打賭,這可以在很多方面進行改進,我將把它留給你......

筆記:

  • 無論我多么努力——我無法讓 GCC默認初始化未使用的數組元素。 我試圖用trick<T>()調用的結果填充它們,但它沒有用......它抱怨未使用的變量並堅持用零填充數組的rest。

     template<class T> T trick() { T r; return r; }
  • 這意味着這個 class 效率很低,更好的方法是使用原始存儲並手動控制它(也許嘗試將數組放入無限制的聯合?但要注意——編譯器在處理聯合時有錯誤

  • 還要記住,編譯器不喜歡太多的 function 參數——相關的優化只適用於相對較小的maxN值。 myarray<1000, int>::make(d, 3)生成的代碼看起來很可怕,編譯時間也很短......

  • myarray ctor 允許類似聚合初始化的初始化,它非常接近但不完全相同。 它不允許就地構造(僅僅是因為 arguments 需要在調用之前構造)——您可以使用inplacer來克服這個問題(參見f()中的示例之一)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM