2016-12-08 2 views
1

Я пытаюсь собрать эффективную структуру C++ 1x, которая может эффективно использовать операции std :: move/copy construct and and assign. Эти структуры относятся к двум основным категориям: структурам POD и структурам, отличным от POD. Я привык писать эти структуры, используя шаблонный код, но я уверен, что компилятор может сделать лучше, чем я, и его довольно много набирать для каждого класса. Мой вопрос - это то, что я могу сделать, чтобы воспользоваться преимуществами операций компилятора по умолчанию. Я знаю, например, что, как только я определяю один явный конструктор, который подавляет автоматическую генерацию операторов перемещения и присваивания. Также мне хотелось бы, чтобы структуры non POD, у которых нет суперклассов, чтобы иметь деструктор по умолчанию, и те, которые наследуют от базовых классов, имеют дефолтный виртуальный деструктор. Правила о том, как делать эти операции эффективно, всегда были немного сбиты с толку.Эффективное создание структур C++ 11 для перемещения и копирования

Оригинальная версия PAGE_DATA структуры является следующим

using PAGE_DATA = struct page_data { 
    std::string name; 
    std::vector<SCRN_TEXT> elements; 
    std::vector<int> jumpTable; 
}; 

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

using PAGE_DATA = struct page_data { 
    explicit page_data(const std::string& rName = std::string(), 
     const std::vector<SCRN_TEXT>& rElements = std::vector<SCRN_TEXT>(), 
     const std::vector<int>& rJumpTable = std::vector<int>()) 
     : name(rName) 
     , elements(rElements) 
     , jumpTable(rJumpTable) 
    {} 
    //! Defaulted copy constructor. 
    page_data(const page_data&) = default; 
    //! Defaulted move constructor. 
    page_data(page_data&&) = default; 

    //! Non-throwing copy-and-swap idiom unified assignment. 
    page_data& operator=(page_data rhs) { 
     rhs.swap(*this); 
     return *this; 
    } 

    //! Non-throwing-swap idiom. 
    void swap(page_data& rhs) noexcept { 
     // enable ADL (not necessary in our case, but good practice) 
     using std::swap; 
     // swap base members 
     // ... 
     // swap members here 
     swap(name, rhs.name); 
     swap(elements, rhs.elements); 
     swap(jumpTable, rhs.jumpTable); 
    } 

    virtual ~page_data() = default; 

    std::string name; 
    std::vector<SCRN_TEXT> elements; 
    std::vector<int> jumpTable; 
}; 

зависимых простого POD структур, которые выкрикивали приведены ниже:

using COLOR_TYPE = enum color_type 
{ 
    BLACK = 0x0, 
    CYAN = 0x1, 
    RED  = 0x2, 
    YELLOW = 0x3, 
    GREEN = 0x4, 
    MAGENTA = 0x5, 
    AMBER = 0x6, 
    WHITE = 0x7 
}; 

using SIZE_TYPE = enum size_type { 
    SMALL_CHAR = 0x0, 
    BIG_CHAR = 0x1 
}; 

using MODIFY_TYPE = enum modify_type { 
    NORMAL  = 0x0, 
    UNDER  = 0x2, 
    FLASH  = 0x4, 
    FLASH_UNDER = 0x6 
}; 

using SCREEN_ATTR = struct screen_attr { 
    COLOR_TYPE color : 4; 
    SIZE_TYPE  size : 2; 
    MODIFY_TYPE blink : 4; 
    unsigned char unused : 6; 
}; 

using CDU_ROWCOL = struct cdu_rowcol { 
    int v; 
    int h; 
}; 

using SCRN_TEXT = struct scrn_text { 
    CDU_ROWCOL loc; 
    SCREEN_ATTR attrib; 
    std::string text; 
}; 

После собирает live coliru demo, я был в состоянии проверить, что котел пластина делает правильную вещь ,.

int main() { 
    std::cout << "assertions work fine" << std::endl; 
    static_assert(std::is_copy_constructible<PAGE_DATA>(), "not copy constructible"); 
    static_assert(std::is_move_constructible<PAGE_DATA>(), "not move constructible"); 
} 
+3

Почему вы настаиваете на том, чтобы придерживаться 'using ALL_CAPS =' перед каждой декларацией структуры? Это не C, где вы делаете «typedef struct». –

+0

@NicolBolas Это псевдоним C++ 11 (современный typedef). Шапки - это псевдоним, а нижний регистр - это структура, это позволяет мне использовать как Typedef, так и Struct вместе, нижний регистр используется для определения сигнатуры конструктора. – johnco3

+3

Я знаю, что означает 'использование' * означает *. Я не знаю, почему вы думаете, что это важно или даже хорошая идея. Как я уже сказал, это не C. В C сама 'struct' не создавала бы имя типа; в C++, это так. 'screen_attr' является * полностью допустимым * именем типа. Вам не требуется typedef/использование 'SCREEN_ATTR'. –

ответ

0

this Мне нравится ответ на мой question, «... если вы оказываетесь писать операторы двигаться и перемещение конструкторов это потому, что вы не достаточно разложить эту проблему.»

3

Ваша первоначальная структура уже была идеально перемещена. Весь дополнительный код шаблона, который вы написали, уже генерируется компилятором, когда это необходимо.

+0

Проблема в том, что мне нужно было добавить явный конструктор по умолчанию, чтобы избежать инициализации скобки. У меня есть векторы этих структур PAGE_DATA. Мне приходилось emplace_back ({..}, {..}, {..}) создавать или создавать локальные структуры PAGE_DATA с использованием агрегатного инициализатора. Также, что произойдет, если у меня есть наследование с непростыми структурами POD. Я не уверен, что происходит в случаях, когда у меня может быть структура Foo: public Bar и как убедиться, что foo делает все правильно с помощью Bar и т. Д., – johnco3

+3

@ johnco3: «* Проблема в том, что мне нужно было добавить явное конструктор по умолчанию, чтобы избежать инициализации скобки. * «... почему вы * хотите *? Вы сделали всех участников * public *; почему вы хотите, чтобы * не позволяли людям использовать агрегатную инициализацию на нем? –

+1

И как только добавление конструктора по умолчанию хуже, чем реализация операций копирования/перемещения? – rubenvb

2

Мой вопрос - это то, что я могу сделать, чтобы воспользоваться преимуществами операций компилятора по умолчанию.

Минимум - это довольно оптимальная сумма - это ваша оригинальная версия, которая в полной мере использует операции по умолчанию.

Ваш page_data::swap, вероятно, немного более эффективным, чем общий std::swap и это не мешает генерации любого неявной функции члена, так что может быть стоит держать. Тем не менее, это, вероятно, лишь незначительно лучше, если вообще, так что вы может захотеть определить, стоит ли загромождать определение вашего класса.