c++ - 为什么静态大小的数组类型不能是容器类型?

标签 c++ stl containers

我有一个静态大小数组的别名,使用起来简单直接:

using triplet_t = std::uint8_t[3];

//           vvvvvvvvvvvvvvvvvv <--- easier than std::uint8_t(&triplet)[3]
void f(const triplet_t &triplet) { /* whatever */ }

triplet_t t{}; // As good as std::uint8_t t[3]{};

t[0] = '0';
t[1] = '1';
t[2] = '2';
for (auto &v : t) std::cout << v << ' ';
std::cout << '\n';

// So far so good...
triplet_t t3[3]{};
for (auto &r : t3)
    for(auto &v : r)
        v = 42;

我什至可以在容器中使用别名:

std::vector<triplet_t> vt;

或者我以前是这么想的,因为一旦你使用 vt 它就会失败:

vt.push_back({});

GCC 8.0.0 201711

error: parenthesized initializer in array new [-fpermissive]
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error: request for member '~unsigned char [3]' in '* __p', which is of non-class type 'unsigned char [3]'
destroy(_Up* __p) { __p->~_Up(); }
                    ~~~~~~^~~

问题似乎是,在展开所有模板技巧后,调用了一个 placement-new 转发所有括号内提供的参数,显然这不是初始化静态大小数组的方法。

此外,容器以某种方式将 triplet_t 视为对象,因此要求析构函数,再次编译失败。如果没有别名,问题显然是一样的:

std::vector<std::uint8_t[3]> vt;
vt.push_back({});          // Boom!
vt.push_back({255, 0, 0}); // Ouch!

但是使用具有相同内存布局的 struct 没问题:

struct rgb { std::uint8_t r, g, b; };
std::vector<rgb> vt;
vt.push_back({});          // Nice!
vt.push_back({255, 0, 0}); // Cool!

我想知道为什么会这样,有没有办法在容器中使用静态大小的数组作为包含类型?

最佳答案

阅读 std::vector documentaion , 你可以找到 T必须满足CopyAssignable的要求和 CopyConstructible。

这意味着(简化):使用 vt T 类型的两个实例, 表达式 t = v必须是合法的。显然,如果 T是 native 数组,但事实并非如此(您不能将 C 数组分配给另一个数组),并且 std::vector<T> 的某些函数会是病式的。

一个解决方案是定义 triplet_t作为:

using triplet_t = std::array<std::uint8_t, 3>;

void f(const triplet_t &triplet) { /* whatever */ }

triplet_t t{};

t[0] = '0';
t[1] = '1';
t[2] = '2';
for (auto &v : t) std::cout << v << ' ';
std::cout << '\n';

// So far so good...
triplet_t t3[3]{};
for (auto &r : t3)
    for(auto &v : r)
        v = 42;

std::vector<triplet_t> vt;

vt.push_back({});

关于c++ - 为什么静态大小的数组类型不能是容器类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47474063/

相关文章:

c++ - 如何在带有来自 std::string 的 unordered_map 的字符串文字上使用 is_transparent 功能?

c++ - 迭代 std::map 的顺序是否已知(并由标准保证)?

c++ - 使用缓冲在 C++ 中逐行读取巨大的文本文件

c++ - 允许将 "const char*"分配给 std::string,但分配给 std::wstring 不会编译。为什么?

c++ - 使用带有冗余信息的键字符串的 map ?

go - 空堆上的容器/堆 Pop()

c++ - "... ..." token 是什么意思?即参数包上的双省略号运算符

c++ - 通过迭代自适应阈值和形状分析检测圆形对象的集群

c++ - 启用 RTTI 的动态_cast 段错误

docker - Docker启动有什么意义吗?