你能`std::move` 一个 `std::vector` 的 `.data()` 吗?

问题描述 投票:0回答:1

这个问题来自于一个 API 的问题,该 API 需要

std::vector<uint8_t>
,但通常从
std::string
s 获取数据。

这就是我试图将

std::move
中的数据
std::string
转换为
std::vector<uint8_t>
:

string data = "Some data";
  
vector<uint8_t> utf8( std::make_move_iterator( data.begin() ),
    std::make_move_iterator( data.end() ) );

// Above doesn't actually move the data,  
puts( data.c_str() ); // Not empty!

有任何线索如何做到这一点吗?

c++ std move
1个回答
0
投票

从技术上讲,是的,但几乎绝对不是你想要的。您可以将

std::move
应用于
.data()
的结果,但是该结果并不引用向量的实际数据 - 它只是指向向量开头的指针。移动该指针意味着移动指针的值,而不是它引用的数据。

您实际上问的是您是否能够做到 - 是否可以简单地移动支持向量的内存并开始将其视为字符串 - 是不可能的。至少标准没有明确规定。在 C++23 中,

std::basic_string
获得了从任意范围构造字符串的能力,并且如果移动的向量作为范围传递(假设它可以 - 请参阅如下),但你不能明确要求。

这样做的原因是因为

std::vector
std::string
具有不同的不变量。乍一看,它们看起来很相似,它们都引用一个固定的内存缓冲区,其中只有该内存的一个子集实际上具有初始化值。然而,更深入地观察,
std::string
还有一个需要保留的额外不变量 - 如果您在字符串上调用
.data()
,第一个
size()
元素将与向量相同,但最后一个之后的元素也相同 必须是空终止符 (0)。如果您要将一个完全充满元素的向量传递给一个字符串,那么该字符串将无法在末尾放置该空终止符,因为没有任何空间。这意味着从向量到字符串执行
std::move
意味着字符串 可能仍会分配内存,这与您在查看代码时可能期望的完全相反。

还有一个问题是,

std::string
std::vector
的工作方式在管理内存方面甚至可能不一样。在转向 SSO 字符串之前,GCC 的
std::string
实现会在其分配的内存中分配大小和引用计数,然后每当您复制字符串时,它都会增加引用计数,但否则会指向相同的内存,并且仅如果您实际修改了字符串,则分配新的内存。在这种情况下,由
std::string
std::vector
分配的内存的内存布局将完全不兼容,因为
std::vector
会使它的字符从分配的内存的开头开始,但
std::string
会让它们从分配的内存开始之后一小段距离,超出了尺寸和引用计数。

© www.soinside.com 2019 - 2024. All rights reserved.