【发布时间】:2019-02-19 16:21:20
【问题描述】:
我正在为网络连接构建一个缓冲区,您可以在其中显式分配内存,或者您可以通过一些顺序容器(例如: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_chunkfunction 基本上只是分配大小的内存,我有 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.这是我的第一篇文章,如果我一开始不准确,请见谅..
【问题讨论】:
-
使用标准容器是不可能的,但你为什么要这样做呢?
-
我不确定您要解决什么问题(我看不出代码与您的问题的其余部分有何关系)。但我认为这可能会对您有所帮助,除非分配器不兼容,否则如果您将
v移动到v_,指向v.data();的指针将指向v_.data();。 -
@marko1777 据我所知,不可能将向量的数据“释放”到这样的原始指针。在
v的生命周期结束后使用p是未定义的行为,尽管我不怀疑这个UB 表现出自己产生了您期望的结果(似乎可以工作)。这不会持久,对代码或其运行的上下文的任何更改都可能改变行为。 -
这是正确的。这对于标准容器本身是不可行的。您将必须实现自己的自定义容器。自定义容器只不过是一个带有
unique_ptr的struct到带有真实数据的std::vector的单个struct,而“不再关心”只不过是将unique_ptr移动到其他地方。 -
将
int *p;更改为std::vector<int>而不是int*。然后使用p = std::move(v);而不是p = v.data();。
标签: c++ c++17 cpp-core-guidelines