我有以下情况:
T* get_somthing(){
std::vector<T> vec; //T is trivally-copyable
//fill vec
T* temp = new T[vec.size()];
memcpy(temp, vec.data(), vec.size() * sizeof(T));
return temp;
}
Run Code Online (Sandbox Code Playgroud)
我希望通过std::vector::data像这样直接返回来摆脱复制过程:
T* get_somthing(){
std::vector<T> vec; //T is trivally-copyable
//fill vec
return temp.data();
}
Run Code Online (Sandbox Code Playgroud)
但是,这是错误的,因为在vec调用析构函数时将删除数据.
那么,如何防止vec删除其数据呢?换句话说,我想从std::vectorC++原始动态数组中获得某种移动idiiom .
PS改变设计不是一种选择.使用std::vector这是强制性的.返回一个pointer到array也是必须的.Becauese它是两个模块之间的包装.一个需要矢量另一个需要指针.
eer*_*ika 19
PS改变设计不是一种选择.使用std :: vector是强制性的.返回指向数组的指针也是必需的.
更改设计是您的最佳选择.我建议重新考虑这个立场.
有(目前†)没有办法来"偷"一个载体的缓冲,所以给出的(傻††在问题陈述)的限制,复制是要走的路.
†Tomasz Lewowski联系了一项提案,如果它包含在未来的标准中,将会改变这一提议:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4359.pdf(编辑:as指出,它被c ++拒绝了17)
††愚蠢直到具体要求合理为止.
它是两个模块之间的包装器.一个需要矢量另一个需要指针.
据推测,需要指针的另一个接口,将缓冲区的破坏委托给调用者,可能使用某种类型的回调void delete_somthing(T*).在我看来,取得所有权而不给予回报将是非常糟糕的设计.
如果你确实控制了破坏,你可以将矢量存储在地图中,并在传递指针进行销毁时删除矢量:
std::unordered_map<T*, std::vector<T>> storage;
T* get_somthing(){
std::vector<T> vec; //T is trivally-copyable
//fill vec
T* ptr = vec.data();
storage[ptr] = std::move(vec);
return ptr;
}
void delete_somthing(T* ptr){
storage.erase(ptr);
}
Run Code Online (Sandbox Code Playgroud)
Tom*_*ski 14
在C++ 11中,没有从向量中释放缓冲区的选项.
这种对标准的扩展是向C++ 17提出的:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4359.pdf但是,正如TC指出的那样,它被拒绝了:https://issues.isocpp.org/show_bug.cgi?id=81
所以没有标准的运气.还发布了一个已经回答的相关问题并解释了同样的问题:在不释放内存的情况下销毁std :: vector
如果您能够使用这些库中的任何一个,您可以尝试自定义分配器或其他奇怪的东西(比如将自己绑定到库的内部实现并弄乱私有矢量数据),但实际上,不要.
下面是如何使用自定义分配器执行此操作的示例代码.这假设您可以vector实际使用自定义分配器.此外,allocator使用静态变量来控制内部缓冲区的破坏.我已经在VS2015下进行了检查,并且它的实现调用仅在内部缓冲区的~vector中释放deallocate - 即它不使用此分配器管理任何其他分配.
这是一个黑客 - 我不确定它的使用会带来什么后果.它确实不是线程安全的(但是在使allow_dealloc线程本地后可以很容易地修复):
http://coliru.stacked-crooked.com/a/5d969a6934d88064
#include <limits>
#include <vector>
#include <iostream>
template <class T>
class my_alloc {
std::allocator<T> alloc;
public:
static bool allow_dealloc;
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
pointer allocate(size_type num, const void* = 0) { return alloc.allocate(num); }
void deallocate(pointer p, size_type num) {
if (allow_dealloc)
alloc.deallocate(p, num*sizeof(T)); }
// Squashed as less important
template <class U> struct rebind { typedef my_alloc<U> other; };
pointer address(reference value) const { return &value; }
const_pointer address(const_reference value) const { return &value; }
my_alloc() throw() { }
my_alloc(const my_alloc&) throw() { }
template <class U> my_alloc(const my_alloc<U>&) throw() { }
~my_alloc() throw() { }
size_type max_size() const throw() { return (std::numeric_limits<size_t>::max)() / sizeof(T); }
void construct(pointer p, const T& value) { alloc.construct(p, value); }
void destroy(pointer p) { p->~T(); }
};
template <typename T>
bool my_alloc<T>::allow_dealloc = true;
int main()
{
int* data = 0;
size_t size = 0;
{
my_alloc<int>::allow_dealloc = true;
std::vector<int, my_alloc<int>> vec= { 0, 1, 2, 3 };
vec.push_back(4);
vec.push_back(5);
vec.push_back(6);
my_alloc<int>::allow_dealloc = false;
data = vec.data();
size = vec.size();
}
for (size_t n = 0; n < size; ++n)
std::cout << data[n] << "\n";
my_alloc<int> alloc;
alloc.deallocate(data, size);
}
Run Code Online (Sandbox Code Playgroud)