【发布时间】:2017-04-23 22:39:21
【问题描述】:
我正在尝试组合一个高效的 C++1x 结构,该结构可以利用高效的 std::move/copy 构造/和赋值操作。这些结构分为 2 个基本类别,POD 结构和非 POD 结构。我已经养成了使用样板代码编写这些结构的习惯,但我很确定编译器在这方面可以做得比我做得更好,而且每个类都需要大量输入。我的问题是利用默认编译器操作我能做的最低限度是什么。例如,我知道,一旦我定义了一个显式构造函数,它就会抑制移动和赋值运算符的自动生成。此外,我希望没有超类的非 POD 结构具有默认析构函数,而那些从基类继承的结构具有默认的虚拟析构函数。如何有效地执行这些操作的规则一直让我有点困惑。
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");
}
【问题讨论】:
-
你为什么要坚持在每个结构声明前加上
using ALL_CAPS =?这不是你typedef struct的东西。 -
@NicolBolas 这是 C++11 的别名(现代 typedef)表示法。 Caps 是别名,小写是 struct,这允许我同时使用 Typedef 和 Struct,小写的用于定义构造函数签名。
-
我知道
using是什么意思。我不知道你为什么认为这样做很重要,甚至是个好主意。就像我说的,这不是 C。在 C 中,struct单独不会创建类型名称;在 C++ 中,确实如此。screen_attr是一个完全有效的类型名称。你不需要 typedef/使用SCREEN_ATTR。
标签: c++11 struct c++14 move defaulted-functions