SMART vector for RAW pointers in C ++ 11?

I am using an old open source library with the following (simplified) API:

// some class that holds a raw pointer to memory on the heap // DOES NOT delete it in its destructor // DOES NOT do a "deep" copy when copied/assigned (ie, after copying both objects // will point to the same address) class Point; // function used to construct a point and allocate its data on the heap Point AllocPoint(); // function used to release the memory of the point data void DeallocPoint(Point& p); // Receives a pointer/c-array of Points, along with the number of points // Doesn't own the memory void Foo(Point* points, int npts); 

What is the best (safest / most readable / most elegant) way to use this API in C ++ 11. I can't just use vector<unique_ptr<Point, PointDeleter>> (where PointDeleter is a simple user-defined divider that I can implement), because then I cannot use the Foo function (which expects Point* , not unique_ptr<Point>* ),

thanks

+6
source share
5 answers

If you really want this to look good, you probably have to write a set of really comprehensive shells that completely hide the library APIs - effectively, wrap the entire library with what behaves in the modern C ++ language from the outside and hides all the mess inside.

Not a pleasant task, but if you can get the behavior of this library, then this should make your life a lot easier in the long run. Not worth it if you will not use this external library very widely, though.

+4
source

I would wrap this non-RAII API in RAII string blocks and then use them in C ++ 11 code.

For example: you can define a RaiiPoint class that wraps a class (not RAII) Point , and in its constructor calls AllocPoint() , in the DeallocPoint() destructor. Then you can define the correct copy constructor and copy operator= or just implement the move semantics (with the move constructor and move operator= ) or make the wrapper class both copyable and movable based on your requirements.

Then you can simply use std::vector<RaiiPoint> with a wrapper class based on RAII.

(This is a general approach that you can use when you want to use C libraries in modern C ++ code: you can wrap the "raw" libraries and objects of the C library in safe RAII boundaries and use these reliable safe wrapper classes in your modern code in C ++.)

+4
source

You can use std::vector<Point> by calling Foo( &v[0], v.size() ) . But managing memory here can be tricky, as Point does not seem to provide any clean copy and purpose; a custom selector in the dispenser will be called for each item, even if it is copied.

If the vector should actually have points, then you can wrap it in a more complex class that calls AllocPoint for each insert (and inserts the results) and DeallocPoint for each delete (and for everything else in the destruction vector). This class should not allow write access to Point (non-const operator[] , non-constant iterators, etc.), however, since this will allow you to change any pointers in Point and lose what is necessary for DeallocPoint to work correctly. Presumably, there are other functions for manipulating Point ; you will need to ensure their availability through the shell interface.

+4
source

You can write a simple shell to free memory:

 struct PointVectorWrapper { vector<Point> points; ~PointVectorWrapper() { for (Point& p : points) { DeallocPoint(p); } } PointVectorWrapper& operator=(const PointVectorWrapper&) = delete; PointVectorWrapper(const PointVectorWrapper&) = delete; }; // Now the usage is simple and safe: PointVectorWrapper points; // ... populate points ... Foo(points.data(), points.size()) 

But that seems a bit "adhoc". What is a more standard / reusable solution?

+1
source

You can use a standard vector with a custom dispenser that calls the AllocPoint method using the build method and DeallocPoint () for the destruct method.

 template<typename T> class CustomAllocator : public std::allocator<T> { //Rebind and constructors }; template<> class CustomAllocator<Point> : public std::allocator<Point> { //Rebind and constructors //For c++11 void construct( pointer p ) { new (p) Point(); *p = AllocPoint(); } void construct( pointer p, const_reference val ) { construct(p); //copy member from val to point if neccessary }; void destroy( pointer p ) { DeallocPoint(*p); p->~Point(); } }; typedef std::vector<Point, CustomAllocator<Point> > PointVector; 
+1
source

Source: https://habr.com/ru/post/947456/


All Articles