Deny std::vector from deleting its data

后端 未结 9 901
天涯浪人
天涯浪人 2021-01-17 11:03

I have the following case:

T* get_somthing(){
    std::vector vec; //T is trivally-copyable
    //fill vec
    T* temp = new T[vec.size()];
    memc         


        
相关标签:
9条回答
  • 2021-01-17 11:36

    I don't know if you will like this very hacky solution, I definitely would not use it in production code, but please consider:

    #include <iostream>
    using namespace std;
    
    #include <vector>
    
    template<class T>
    T* get_somthing(){
        std::vector<T> vec = {1,2,3}; //T is trivally-copyable
    
        static std::vector<T> static_vector = std::move(vec);
    
        return static_vector.data();
    }  
    
    int main() {
        int * is = get_somthing<int>();
        std::cout << is[0] << " " << is[1] << " " << is[2];
        return 0;
    }
    

    so, as you can see inside the get_somthing I define a static vector, of same type as you need, and use std::move on it, and return it's data(). It achieves what you want, but this is dangerous code, so please use the good old fashioned copy the data again methodology and let's wait till N4359 gets into the mainstream compilers.

    Live demo at: http://ideone.com/3XaSME

    0 讨论(0)
  • 2021-01-17 11:37

    Isn't the way to go here simply to allocate the vector dynamically? That's how resources with a life time which is unrelated to scope are traditionally managed, and I don't see any reason to invent something extraordinary.

    Of course that vector should be destroyed some time later; that may make it necessary to store its address somewhere as a side effect of get_somthing(), but even then this strategy seems cleaner than any of the other ideas.

    0 讨论(0)
  • 2021-01-17 11:37

    Ok, don't try this at home, it's not nice. It's more an experiment than an actual answer.

    (Well, the requirements/design is not nice either: "Play stupid games, win stupid prizes")

    in your cpp:

    #define private public               // good luck for the code review
    #define protected public
    #include <vector>                    // (must be the first occurence in the TU)
    #undef private                       // do not abuse good things...
    #undef protected
    
    template<typename T>
    T* my_release(std::vector<T>& v){
        std::vector<T> x;                // x: the local vector with which we mess around
        std::swap(x, v);                 // the given vector is in an OK, empty state now.
        T* out = x._M_impl._M_start;     // first, get the pointer you want
    
        // x will be destructed at the next '}'. 
        // The dtr only use _M_start and _M_finish, make sure it won't do anything.
        x._M_impl._M_start = nullptr;    
        x._M_impl._M_finish = nullptr;
    
        // no need to say, the internal state of 'x' is bad, like really bad...
        // also we loose the capacity information, the actual allocator... 
        // -> good luck with memory leaks...
    
        return out;
    }
    
    // usage example
    int main(){
        std::vector<int> vi{1,2,3,4,5,6,7,8,9};
        auto n = vi.size();
        int* pi = release(vi);
        for(size_t i=0; i<n; ++i)
            std::cout << pi[i] << ", ";
    
        return 0;
    }
    

    prints 1, 2, 3, 4, 5, 6, 7, 8, 9,

    0 讨论(0)
  • 2021-01-17 11:38

    If there is an option to use smart pointers I would recommend std::shared_ptr with alias:

    template<typename T>
    std::shared_ptr<T> get_somthing(){
        using Vector = std::vector<T>;
        using ReturnT = std::shared_ptr<T>;
        std::vector<T>* vec = new std::vector<T>;
        //fill vec
        std::shared_ptr<Vector> vectorPtr(vec); // (1)
        std::shared_ptr<T> aliasedPtr(vectorPtr, vec->data()); // (2)
        return aliasedPtr;
    }
    

    (1) will create a shared pointer to the vector to be aliased to (2) creates a shared pointer that will destroy the aliased shared_ptr instead of removing contained data

    0 讨论(0)
  • 2021-01-17 11:39

    Below is sample code how to do it with custom allocator. This assumes you can make vector actually use custom allocator. Also allocator uses static variable to control destruction of internal buffer. I have checked under VS2015 and its implementation calls deallocate in ~vector only for internal buffer - i.e. it does not manage any other allocations using this allocator.

    This is a hack - and I am not sure what consequences its use might have. Its not thread safe for sure (but could be easily fixed after making allow_dealloc thread local).:

    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);
    }
    
    0 讨论(0)
  • 2021-01-17 11:40

    In C++11 there is no option to release the buffer from the vector.

    Such extension to standard was proposed to C++17: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4359.pdf but, as T.C. pointed out, it was rejected: https://issues.isocpp.org/show_bug.cgi?id=81

    So no luck in the standard for that. Also a related question was posted that is already answered and explains the same problem: Destroy std::vector without releasing memory

    If you are able to mess with either of these libraries you can try custom allocators or other weird stuff (like binding yourself to internal implementation of library and messing with private vector data), but really, don't.

    0 讨论(0)
提交回复
热议问题