C++11 可以将std::数组移动到std::vector中吗?

C++11 可以将std::数组移动到std::vector中吗?,c++11,move,heap-memory,stdarray,stack-memory,C++11,Move,Heap Memory,Stdarray,Stack Memory,这是一个关于堆栈内存和堆内存交互的问题,以及通过std::array和std::vector类从堆栈到堆的特殊情况 原则上,std::array可以看作是指向第一个元素的指针,加上一些关于数组大小的编译时信息。有没有可能让std::vector构造函数考虑到这一事实,并尝试通过复制指针将数组的内容移动到vector中 一个用例是,一个函数返回一个std::array std::array fun(){…} 但后来人们决定将其分配给std::vector,而无需逐元素复制 std::vector

这是一个关于堆栈内存和堆内存交互的问题,以及通过
std::array
std::vector
类从堆栈到堆的特殊情况

原则上,
std::array
可以看作是指向第一个元素的指针,加上一些关于数组大小的编译时信息。有没有可能让
std::vector
构造函数考虑到这一事实,并尝试通过复制指针将
数组的内容移动到
vector

一个用例是,一个函数返回一个
std::array

std::array fun(){…}

但后来人们决定将其分配给
std::vector
,而无需逐元素复制

std::vector v=fun();//不工作代码

现在必须做的就是

std::array<double, 20> tmp = fun();
std::vector<double> v(tmp.begin(), tmp.end());
有没有一种方法可以将内存从堆栈移动到堆(不管这意味着什么)以及是否可以与移动构造函数结合使用

我个人喜欢“不管那意味着什么”这一点。让我们思考一下。将某个对象从一个堆栈移动到另一个堆栈会突然意味着堆栈的这部分突然被标记为一个堆分配的区域,并受到定期破坏

问题是堆栈是连续的,并且会被从堆栈中弹出的东西破坏。你不能只说“嘿,把这个内存位留下”——任何连续的堆栈分配和释放都需要跳过这个部分

举例说明:

|                      |
|----------------------|
| stack block 1        |
|----------------------|
| your vector          |
|----------------------|
| stack block 2        |
|----------------------|
|-                    -|
如果要展开这两个块,首先需要将堆栈指针减小块2指针的大小,然后减小向量和块1的大小。这真的不可能发生

因此,这里唯一可行的解决方案是将副本复制到堆内存区域。然而,这些拷贝比很多人预期的要快得多。即使向量有几兆字节,我想内存控制器也可以交换一些页面,而不必实际发送与数据位对应的电信号


此外,向量的任何大小调整都需要引起重新分配。由于数组占用的内存正好与它所需的一样多,因此即使添加一个元素也会触发您试图避免的复制。

似乎您希望告诉
std::vector
使用
std::array
数据作为其底层缓冲区,至少在它需要重新分配之前是这样

std::vector
没有此接口。它应该自行管理其内部缓冲区,以便以统一的方式分配、跟踪和删除内存。如果您可以提供一个缓冲区来使用,那么您还需要提供有关如何分配缓冲区的信息,以及在离开作用域时它是否会被破坏等。这很容易出错,而且很难看,因此不可用

您可以使用s构造
std::vector
,将内容移出
std::array
。当然,这对算术类型没有影响,但对于逻辑上大的对象(移动成本低),它可以避免大量数据复制:

std::array<BigThing, 20> a = fun();
std::vector<BigThing> b { std::make_move_iterator(a.begin()),
                          std::make_move_iterator(a.end())) };
std::数组a=fun();
std::vector b{std::make_move_迭代器(a.begin()),
std::make_move_迭代器(a.end())};

如果将数组移动到向量中,然后推回()一个新元素会怎么样?@AntonioPérez,这一点很好,但我想
std::vector
会像往常一样,重新分配(保留)更多内存(可能在内存中的其他地方)。优化将丢失,但问题并非如此。对于
vector
类,可能会以有限的方式使用“小向量优化”。仍然排除未使用此优化的
std::vector
(但
std::basic_string
使用)的AFAIK。也可能是
std::vector
的某个特殊化,带有一个特定的(伪)分配器,如下面的一条注释中所示。您可以使用自定义分配器,如Howard Hinnant的
short\u alloc
。我看到的主要问题是
vector
管理它自己的大小,你需要黑客用一个已经填充的数组来初始化它(比如
resize
加上一个自定义分配器::构造,当请求值init时它不执行任何初始化)。@dyp,是的,我想了解一下将从提供的数组模拟内存分配的自定义分配器。问题(可能是不可避免的)是,在任何时候(取决于范围)
std::array
本身都可能消失。(为了使问题简单,我没有提到自定义分配器黑客)。一种选择可能是以某种方式使数组析构函数调用“消失”,但即使这是可能的,它也会违反堆栈行为的一些约束(请参见@Bartek的答案)。我不知道
move\u iterator
@dyp在不破坏分配器契约的情况下是否可能?找到它:另请参见:伟大的答案。我想一切都可以归结为“堆栈和堆只能通过复制进行通信”。一个有趣的细节是,在用例中,数组中的内存在传输(复制或移动)到“std::vector”时位于堆栈顶部。是的,如果向量稍后增长,优化将丢失,因为必须重新分配内存。但只有到那时,如果它保持不变,那么它仍然是正常的。“即使向量有几兆字节,我想内存控制器也可以交换一些页面,而不必物理地发送与数据位对应的电信号。”我不这么认为。当向量开始复制位时,页面将已经由
malloc
(或类似)分配,并且操作系统不知道何时保留这些页面,它们最终将包含在其中
std::array<BigThing, 20> a = fun();
std::vector<BigThing> b { std::make_move_iterator(a.begin()),
                          std::make_move_iterator(a.end())) };