我正在为网络连接建立一个缓冲区,您可以在其中显式分配内存,也可以通过一些顺序的容器(例如:std :: vector,std :: array)自行提供这些内存块存储在列出我们稍后用于读/写操作的列表。 (需要块来处理多个读/写请求) 关于最后一部分,我有一个问题,我想创建一个指向容器数据的指针,然后告诉容器不再关心它的数据了。 所以像移动语义。
std::vector<int> v = {9,8,7,6,5,4,3,2,1,0};
std::vector<int> _v(std::move(v));
_v
的所有v
和v
值都处于安全状态。
问题是,如果我只是在容器的生存期结束后为v.data()
创建一个指针,则该指针所指向的数据将随容器一起释放。
例如:
// I would use span to make sure It's a sequential container
// but for simplicity i use a raw pointer
// gsl::span<int> s;
int *p;
{
std::vector<int> v = {9,8,7,6,5,4,3,2,1,0};
// s = gsl::make_span(v);
p = v.data();
}
for(int i = 0; i < 10; ++i)
std::cout << p[i] << " ";
std::cout << std::endl;
现在p
包含一些内存垃圾,我需要该向量先前拥有的内存。
我也尝试过v.data() = nullptr
,但是v.data()
是右值,因此无法分配它。您有什么建议吗,或者有可能吗?
编辑。: 为了更清楚地说明我要实现的目标:
class readbuf_type
{
struct item_type // representation of a chunk
{
uint8_t * const data;
size_t size;
inline item_type(size_t psize)
: size(psize)
, data(new uint8_t[psize])
{}
template <std::ptrdiff_t tExtent = gsl::dynamic_extent>
inline item_type(gsl::span<uint8_t,tExtent> s)
: size(s.size())
, data(s.data())
{}
inline ~item_type()
{ delete[] data; }
};
std::list<item_type> queue; // contains the memory
public:
inline size_t read(uint8_t *buffer, size_t size); // read from queue
inline size_t write(const uint8_t *buffer, size_t size); // write to queue
inline void *get_chunk(size_t size)
{
queue.emplace_back(size);
return queue.back().data;
}
template <std::ptrdiff_t tExtent = gsl::dynamic_extent>
inline void put_chunk(gsl::span<uint8_t,tExtent> arr)
{
queue.emplace_back(arr);
}
} readbuf;
我有get_chunk
函数,基本上只按大小分配内存,而我却有put_chunk
苦苦挣扎,之所以需要它,是因为在您可以写入此队列之前,需要分配内存,然后将尝试写入的缓冲区(向量,数组)中的所有元素复制到队列中。
像这样:
std::vector<int> v = {9,8,7,6,5,4,3,2,1,0};
// instead of this
readbuf.get_chunk(v.size);
readbuf.write(v.data(), v.size());
// we want this
readbuf.put_chunk({v});
由于我们正在开发分布式系统,因此内存至关重要,这就是为什么我们要避免不必要的分配,复制。
ps。这是我的第一篇文章,很抱歉,如果我不是很精确。
答案 0 :(得分:4)
否,不可能以您建议的方式“窃取”标准向量的缓冲区-或任何其他与此有关的标准容器。
您已经展示了一种解决方案:将缓冲区移到另一个向量中,而不仅仅是获取缓冲区的地址(或另一个非所有者引用)。从向量移出将转移内部缓冲区的所有权。
有可能实现这样的自定义矢量类,其缓冲区可能被盗,但是矢量无法实现这一点是有原因的。如果您随意地释放资源,很难证明程序的正确性。您是否考虑过如何防止数据泄漏?上面的解决方案更简单,更容易验证正确性。
另一种方法是重新构建程序,以使对容器数据的引用不会超出容器本身(或任何无效操作)。
答案 1 :(得分:1)
不幸的是,向量的存储区域无法与std :: vector对象分离。即使将某些数据插入到std :: vector对象,也可以删除该存储区。因此,除非您确定此特定的std :: vector对象存在并且未被修改,否则以后使用此存储区是不安全的。
此问题的解决方案是分配一个新的存储区,并将向量的内容复制到此新分配的存储区。可以安全地访问新分配的内存区域,而不必担心std :: vector对象的状态。
std::vector<int> v = {1, 2, 3, 4};
int* p = new int[v.size()];
memcpy(p, v.data(), sizeof(int) * v.size());
使用完该存储区后,别忘了删除该存储区。
delete [] p;
答案 2 :(得分:0)
您的错误是在认为指针“包含”内存。它不包含任何东西,垃圾,整数或其他。它是一个指针。它指向东西。您已经删除了这些内容,并且没有将其转移到其他任何地方,因此它不再起作用。
通常,您将需要一个容器来放置此信息,它可以是另一个向量,甚至是您自己的手工数组。仅具有指向数据的指针并不意味着您具有数据。
此外,由于不可能要求向量将其缓冲区释放为非向量对象,因此在这种特殊情况下,向量实际上是您唯一的机会。尚不清楚为什么这对您来说还不够好。 :)
答案 3 :(得分:0)
不确定您要达到什么目的,但我会使用这样的移动语义:
#include <iostream>
#include <memory>
#include <vector>
int main() {
std::unique_ptr<std::vector<int>> p;
{
std::vector<int> v = {9,8,7,6,5,4,3,2,1,0};
p = std::move(make_unique<std::vector<int>>(v));
}
for(int i = 0; i < 10; ++i)
std::cout << (*p)[i] << " ";
std::cout << std::endl;
return 0;
}