Const
Const

Reputation: 1356

Efficient way of providing an initializer list constructor

Let's say, a class Base with following resorces:

struct Base
{
    int m_int;
    bool m_flag;
    float m_float;
    Base() = delete; // just to see that it didn't call
    Base(int a, bool b, float c): m_int(a), m_flag(b), m_float(c) {}

};

Then I have a SubClass which has a vector of Base class as the resource.

Then I came up with following code for my SubClass.

struct SubClass
{
private:
    std::vector<Base> vec;
public:
    SubClass() = delete; // just to see that it didn't call

    // Idea - 1
    //SubClass(std::initializer_list<Base>&& all): vec(std::move(all)) {}

    // Idea - 2
    SubClass(std::initializer_list<Base> all): vec(all) {}

    // Idea - 3 : but no more list initialization possible
    template<typename ...Arg>
    void addToClass(Arg&& ...args)
    {
        vec.emplace_back(std::forward<Arg>(args)...);
    }
};

Then in the main(), I can have following two possibilities to update resources in SubClass:

int main()
{
    // possibility - 1
    SubClass obj
    {
       {1, true, 2.0f },
       {5, false, 7.0f},
       {7, false, 9.0f},
       {8, true, 0.0f},
    };
    //possibility - 2: without list initialization
    /*obj.addToClass(1, true, 2.0f);
    obj.addToClass(5, false, 7.0f);
    obj.addToClass(7, false, 9.0f);
    obj.addToClass(8, true, 0.0f);*/

    return 0;
}

Question - 1:

Which one of following is efficient or good to use(good practice) in above case? Why?

// Idea - 1
SubClass(std::initializer_list<Base>&& all): vec(std::move(all)) {}

// Idea - 2
SubClass(std::initializer_list<Base> all): vec(all) {}

Question - 2:

Does addToClass(Arg&& ...args) function works similar to any of the above two ideas?

Upvotes: 0

Views: 609

Answers (1)

NathanOliver
NathanOliver

Reputation: 180825

First things first.

SubClass(std::initializer_list<Base>&& all): vec(std::move(all)) {}

and

SubClass(std::initializer_list<Base> all): vec(all) {}

Don't do the same thing. The first also needs

SubClass(std::initializer_list<Base>& all): vec(all) {}

So you can initialize it with an lvalue std::initializer_list (may never happen but it could). Passing by value covers both of those overloads so it is easier to write and it's performance is just about as good (it would take a lot of operations to really make a difference)

You can't move objects out of a std::initializer_list since the objects as marked as const so

SubClass(std::initializer_list<Base>&& all): vec(std::move(all)) {}

doesn't actually move anything.

As for addToClass you can have both. You can have your template version that emaplces a single object into the class. You can also add an overload to take a std::initializer_list so you can add multiple objects like

void addToClass(std::initializer_list<Base> all)
{
    vec.insert(vec.end(), all.begin(), all.end());
}

and that will add all of the objects in all to the end of vec.

Upvotes: 1

Related Questions