Эффективный способ предоставления конструктора списка инициализаторов - PullRequest
0 голосов
/ 25 июня 2018

Скажем, класс Base со следующими ресурсами:

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) {}

};

Тогда у меня есть SubClass, у которого вектор класса Base является ресурсом.

  • После исследования я обнаружил, что с помощью идеальной ссылки пересылки или пересылки ресурсы класса Base могут создаваться намного эффективнее, поскольку это позволяет избежать ненужного вызова конструкторов по умолчанию (пожалуйста, исправьте меня, если я ошибаюсь).
  • В дополнение к технике пересылки я хотел также иметь конструктор списка инициализаторов, чтобы можно было использовать агрегирование для SubClass

Затем я подошелсо следующим кодом для моего 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)...);
    }
};

Затем в main() я могу иметь следующие две возможности для обновления ресурсов в 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;
}

Вопрос - 1:

Что из перечисленного ниже эффективно или целесообразно использовать (хорошая практика) в вышеуказанном случае?Зачем?

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

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

Вопрос - 2:

Работает ли функция addToClass(Arg&& ...args) аналогично любой из двух вышеупомянутых идей?

1 Ответ

0 голосов
/ 25 июня 2018

Перво-наперво.

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

и

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

Не делайте то же самое.Для первого также требуется

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

Так что вы можете инициализировать его lvalue std::initializer_list (может никогда не произойти, но могло бы).Передача по значению покрывает обе эти перегрузки, поэтому их легче писать, а производительность почти такая же хорошая (для того, чтобы действительно изменить ситуацию, потребуется много операций)

Вы не можете перемещать объекты изstd::initializer_list, поскольку объекты, помеченные как const, так что

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

фактически ничего не перемещают.

Что касается addToClass, то вы можете иметь и то, и другое.У вас может быть версия шаблона, которая отображает один объект в классе.Вы также можете добавить перегрузку для получения std::initializer_list, чтобы вы могли добавить несколько объектов, таких как

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

, и это добавит все объекты в all в конец vec.

...