拒绝std :: vector删除其数据

Hum*_*awi 16 c++ vector c++11

我有以下情况:

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这是强制性的.返回一个pointerarray也是必须的.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)

  • 我可以说拒绝`vector :: release()`提议.通常(使用现代自定义分配器),正确处理向量资源(正确实现`~vector()`)不是初学者代码.只是在那个指针上调用`delete []`就不正确了,即使你知道`vector`正在使用`std :: allocator`.当你正确地构建释放`vector :: release()`返回的指针所需的所有机制时,你已经重新创造了一大块`vector`.使用比unique_ptr <T []> :: release()`更难以使用的数量级. (11认同)

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

如果您能够使用这些库中的任何一个,您可以尝试自定义分配器或其他奇怪的东西(比如将自己绑定到库的内部实现并弄乱私有矢量数据),但实际上,不要.


mar*_*inj 6

下面是如何使用自定义分配器执行此操作的示例代码.这假设您可以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)