initialize std::array without copying/moving elements
Asked Answered
M

2

9
#include <iostream>
#include <string>
#include <array>

class C {
private:
    std::string a;
    std::string b;
    std::string c;
public:
    C(std::string a_, std::string b_, std::string c_) : a{a_},b{b_},c{c_} {}
    ~C(){};
    C(const C&) =delete;
    C(const C&&) =delete;
    const C& operator=(const C&) =delete;
    const C& operator=(const C&&) =delete;
};

std::array<C,2> array = {C("","",""),C("","","")};

int main()
{}

this won't compile (Android Studio with NDK and clang) with a "call to deleted constructor of c" error. I know that I can e.g. use a std::vector and emplace_back() to construct an element directly inside the container, but in my code I want to only use fixed-sized containers and non-copyable/moveable objects for optimization. I'm probably missing sth basic here, but isn't there a way to initialize the std::array without first having to construct the individual elements and then copy them there?

Marino answered 9/2, 2017 at 16:36 Comment(1)
By the way you don't need to put those underscores in your parameter names. C(std::string a, std::string b, std::string c) : a{a},b{b},c{c} {} has no ambiguity issues and does what you expect.Ferry
N
8

You can use brace enclosed initializers instead of temporary c objects:

std::array<c,2> array = {{{"",""},{"",""}}};

or

std::array<c,2> array{{{"",""},{"",""}}};
Nonfiction answered 9/2, 2017 at 16:41 Comment(4)
Is it a portable solution? I mean it depends on how std::array is implemented, it must contain exactly one element of type T[N].Gelderland
@Gelderland I am pretty sure of it. Last time I checked the requirement was not that std::array contain exactly one element of type T[N], but that it behave as if it did. There was a whole issue about whether the middle {} could be omitted, i.e. whether this should also be valid: {{"",""}, {"",""}}. That last thing may have changed since C++11.Nonfiction
I am asking because I was reading one SO where T.C. said that it is not guaranteed: #27669700 .Gelderland
@Gelderland For the above syntax to work, there is no need for a single data member requirement.Nonfiction
T
6

It would become possible since C++17, from that for some specified cases copy elision is guaranteed.

Under the following circumstances, the compilers are required to omit the copy- and move- constructors of class objects even if copy/move constructor and the destructor have observable side-effects:

  • In initialization, if the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object:

    T x = T(T(T())); // only one call to default constructor of T, to initialize x
    

And for these cases, copy/move constructor is not required to be accessible.

When copy-elision takes place (until C++17) In those cases where copy-elision is not guaranteed, if it takes place (since C++17) and the copy-/move-constructor is not called, it must be present and accessible (as if no optimization happened at all), otherwise the program is ill-formed.

LIVE

Tush answered 9/2, 2017 at 16:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.