Convert vector to owned array without copying - c++

A std::vector is more or less this:
class vector {
T* array;
size_t length;
size_t capacity;
public:
...
}
Is it possible to extract the array object, taking ownership of it without copying any data? In other words, so that this is a valid program with no undefined behaviour or memory leaks.
int main() {
vector<int> foo = {1, 2, 3};
int* fooArray = foo.magical_extraction_method();
delete[] fooArray;
}
To be clear, I am not looking for foo.data(), &foo[0] or similar. I want ownership of the underlying array.

Is it possible to extract the array object, taking ownership of it
No, there is no standard way to extract ownership from a std::vector. Except into another vector (using move).
delete[] fooArray;
delete[] is only allowed on a pointer returned by new[]. A std::vector never owns such pointer.

Yes, using unique_ptr with a custom deleter:
template<class T>
struct VectorDeleter {
explicit constexpr VectorDeleter(std::vector<T> v) noexcept : v{std::move(v)} {};
VectorDeleter(VectorDeleter&&) = default;
VectorDeleter& operator=(VectorDeleter const&) = delete;
std::vector<T> v;
void operator()(T* p) {
assert(p == v.data());
v.clear();
}
};
template<class T>
std::unique_ptr<T[], VectorDeleter<T>> release(std::vector<T>&& v) {
auto const p = v.data();
return std::unique_ptr<T[], VectorDeleter<T>>{p, VectorDeleter<T>{std::move(v)}};
}
Example.
There is nothing in the standard that can manage the memory of a std::vector other than the same std::vector. Mostly, this is because any number of elements from 0 to capacity() may have been constructed, and these elements only must be destructed before freeing the memory.

Related

Initialize new[] using copy constructor

I believe this is a simple question with probably a not simple answer.
Here is the code:
template<typename T>
T* copy(T* original, int size) {
T* result = new T[size];
// At this point the default constructor of all new T objects have been called.
for(int i = 0; i < size; ++i) {
// This will call the assignment operator= on all new T objects
result[i] = original[i];
}
return result;
}
Question:
Is there a way to initialize the newly allocated memory using the copy constructor of T instead of using default constructor followed by assignment operator?
The purpose is to copy each element to its analogous element in the new array using the copy constructor of T.
I imagine there could be a way to do that by allocating memory using malloc, then calling the copy constructor for each element but I don't know how.
Here is an example solution from my imagination. If this is correct or this is the best we can get, tell me. Or propose a better solution:
template<typename T>
T* copy(T* original, int size) {
T* result = malloc(sizeof(T)*size);
// At this point the default constructor of all new T objects have been called.
for(int i = 0; i < size; ++i) {
T t(original[i]);
memcpy(result+i*sizeof(T), &t, sizeof(T));
}
return result;
}
Note: Raw pointers are being used for simplicity.
Note 2: I don't need a vector. This pattern will be used to copy the underlying data structure of more complicated objects.
You will have to allocate memory by any other means, but keep in mind that size * sizeof(T) can overflow. std::allocator takes care of this.
Use std::uninitialized_copy/std::uninitialized_copy_n to perform the copy:
template<typename T>
T* copy(T* original, int size) {
std::allocator<T> alloc;
T* result = alloc.allocate(size);
try {
std::uninitialized_copy_n(original, size, result);
} catch (...) {
alloc.deallocate(result, size);
throw;
}
return result;
}
Later you can use std::destroy/std::destroy_n to destroy them and deallocate memory:
template<typename T>
void destroy(T* ptr, int size)
{
std::destroy_n(ptr, size);
std::allocator<T>().deallocate(ptr, size);
}
This should work unless you need to be able to delete them with operator delete[] - in which case there is no solution for this.
If you are implementing a custom container, you can use template allocator like standard containers do:
template<typename T, typename Allocator = std::allocator<T>>
struct container
{
[[no_unique_address]] Allocator allocator;
...
};
For the new operator I don't think so.
But yes there is. It's called std::vector:
template<typename T>
std::vector<T> copy(T* original, int size) {
return std::vector<T>{original, original + size};
}
Because you don't follow RAII and use owning raw pointers your code is not memory leak free, so don't do that! Use C++ properly.

Can I force std::vector to leave a memory leak?

Can I force std::vector to not deallocate its memory after the vector goes out of scope?
For example, if I have
int* foo() {
std::vector<int> v(10,1); // trivial vector
return &v[0];
}
int main()
{
int* bar = foo();
std::cout << bar[5] << std::endl;
}
There is no guarantee that the values will still be accessible here.
I am currently simply doing this
int* foo() {
std::vector<int> v(10,1);
int* w = new int[10];
for (int i=0; i<10; i++) {
w[i] = v[i];
}
return w;
}
but it is a little wasteful to repopulate a whole new array. Is there a way to force std::vector to not delete its array?
Note: I am not returning the vector itself because I am interfacing c++ with python using SWIG, and ARG_OUTVIEW_ARRAY requires a raw pointer and, in fact, an intentional memory leak. I would still however like to be able to make use of vector features while constructing the data itself.
It is possible but you should never do it. Forcing a vector to leave memory leak is a terrible idea and if you need such a thing then you need to re-think your design. std::vector is a resource managing type whose one of the main goals is to ensure that we don't have a leak. Never try to break that.
Now, to answer your specific question: std::vector takes an allocator type as second template parameter which is default to std::allocator<T>. Now you can write a custom allocator that doesn't release any memory and use that with your vector. Writing a custom allocator is not very trivial work, so I'm not going to describe that here (but you can Google to find the tutorials).
If you really want to use custom allocator then you must ensure that your vector never triggers a grow operation. Cause during growing capacity the vector will move/copy data to new location and release the old memories using the allocator. If you use an allocator that leaks then during growing you not only retain the final data, but also retain the old memories which I'm sure that you don't want to retain. So make sure that you create the vector with full capacity.
The vector is desiged to prevent leaks.
But if you want to shoot yourself in the foot, it's possible. Here's how you prevent the vector from deallocating its internal array:
int *foo()
{
std::vector<int> v(10,1);
int *ret = v.data();
new (&v) std::vector<int>; // Replace `v` with an empty vector. Old storage is leaked.
return ret;
}
As the other answers say, you should never do it.
No.
Vectors are not implemented to have memory leaks, and the interface does not provide a way to create one.
You can't "steal" the memory (removing ownership of it from the vector), which is possibly a bit of a shame.
Sorry, but you are going to have to either copy (as you're doing now), or not use vector.
This is a bad idea, but possible by creating a custom allocator that does not deallocate as said in other answers.
For example : (boilerplate mostly from cppref)
#include <cstdlib>
#include <new>
#include <vector>
template <typename T>
struct LeakingAllocator
{
using value_type = T;
LeakingAllocator() = default;
template <typename U> constexpr LeakingAllocator(const LeakingAllocator<U>&) noexcept {}
T* allocate(std::size_t n)
{
if(n > std::size_t(-1) / sizeof(T)) throw std::bad_alloc(); // check for overflow
if(auto p = static_cast<T*>(std::malloc(n*sizeof(T)))) return p; // return p if malloc returns a valid object
throw std::bad_alloc(); // otherwise just throw.
}
void deallocate(T* p, std::size_t) noexcept { /*leak intentionally*/ }
};
template <typename T, typename U>
bool operator==(const LeakingAllocator<T>&, const LeakingAllocator<U>&) { return true; }
template <typename T, typename U>
bool operator!=(const LeakingAllocator<T>&, const LeakingAllocator<U>&) { return false; }
template <typename T>
using LeakingVector = std::vector<T, LeakingAllocator<T>>;
Then code like
int* ret()
{
LeakingVector<int> a;
a.resize(10);
return &a[0];
}
int main()
{
auto ptr = ret();
*ptr = 10;
std::cout << *ptr;
}
becomes valid.
Not sure but, yes.
You can create a custum allocator who do nothing when deallocate => leak
Or may be you can jsut create your vectoron the heap so it will leak anyway.
int* foo() {
std::vector<int>* v = new std::vector<int>(10,1);
return &((*v)[0]);
// no delete
}
int main()
{
int* bar = foo();
std::cout << bar[5] << std::endl;
}
No.
And you're doing it wrong. Return the vector instead so the lifetime works out:
Write your own special Python memory vector class, something like (most crudely):
template <typename T>
class python_vector
{
T* buffer_;
public:
python_vector(size_t n, const T& value) : buffer_{new T(n)}
{}
// copy, assignment, operator[](), *etc*
~python_vector()
{
// DO NOTHING!
}
}
python_vector<int> foo() {
python_vector<int> v(10,1);
// process v
return v;
}
int main()
{
python_vector<int> bar = foo(); // copy allusion will build only one python_vector here
std::cout << bar[5] << std::endl;
}
In C++ you would most probably write:
auto foo()
{
std::vector<int> v(10,1); // trivial vector
return v;
}
int main()
{
const auto bar = foo();
std::cout << bar[5] << std::endl;
}

Create an object array without calling the constructors

for an embedded system we need a custom vector class, where the capacity is set during compile-time through a template parameter.
Until now we had an array of objects as a member variable.
template<class T, size_t SIZE>
class Vector {
...
T data[SIZE];
}
The problem here of course is that if T isn't a POD, the default constructors of T are called. Is there any way to let data be uninitialized until a corresponding push() call (with placement new inside)? Just using
uint8_t data[SIZE * sizeof(T)];
possibly breaks the alignment of T. We absolutely cannot use dynamic memory, the total container size always needs to be known at compile-time. We also cannot use C++'s alignas specifier since the compiler does not support C++11 yet :(
First I would check if the compiler has support for alignment, ie gcc has __attribute__(aligned(x)), there is likely something similar.
Then if you absolutely have to have aligned uninitialized data without such support, you will have to waste some space
// Align must be power of 2
template<size_t Len, size_t Align>
class aligned_memory
{
public:
aligned_memory()
: data((void*)(((std::uintptr_t)mem + Align - 1) & -Align)) {}
void* get() const {return data;}
private:
char mem[Len + Align - 1];
void* data;
};
And you'd use placement new with it
template<typename T, size_t N>
class Array
{
public:
Array() : sz(0) {}
void push_back(const T& t)
{
new ((T*)data.get() + sz++) T(t);
}
private:
aligned_memory<N * sizeof(T), /* alignment */> data;
size_t sz;
};
Live
The alignment of T can be found with C++11 alignof, check your compiler to see if it supports anything that can be used to find out its alignment. You can also just take a guess from printed pointer values and hope that's enough.
Another way is to use std::vector<> with a custom allocator that allocates on the stack.
This way you would create an empty vector, reserve the required space, which should be equal to the space your allocator allocates for you on the stack, and then populate the vector using vector<>::emplace_back. Your element type can be non-copyable but must be movable in this case.
E.g.:
#include <vector>
struct X {
X(int, int);
// Non-copyable.
X(X const&) = delete;
X& operator=(X const&) = delete;
// But movable.
X(X&&);
X& operator=(X&&);
};
template<class T, std::size_t N>
struct MyStackAllocator; // Implement me.
int main() {
std::vector<X, MyStackAllocator<X, 10>> v;
v.reserve(10);
v.emplace_back(1, 2);
v.emplace_back(3, 4);
}
Information about how to implement an allocator is widely available, for example, search YouTube for "c++ allocator".
You are going to have to use placement new along with a union trick to get the alignment properly set.
// use `std::max_align_t` and `std::aligned_storage` when you have it
// since don't have access to alignof(), use the presumably max
// alignment value
using MaxAlign = long;
template <typename T, int size>
class UninitializedArray {
union Node {
char data[sizeof(T)];
MaxAlign alignment;
};
Node aligned_data[size];
bool initialized;
public:
UninitializedArray() : initialized(false) {}
void initialize() {
for (int i = 0; i < static_cast<int>(size); ++i) {
new (&this->aligned_data[i].data) T();
}
this->initialized = true;
}
~UninitializedArray() {
if (this->initialized) {
for (int i = 0; i < static_cast<int>(size); ++i) {
T* ptr = reinterpret_cast<T*>(&this->aligned_data[i].data);
ptr->~T();
}
}
}
T& operator[](int index) {
if (!this->initialized) {
this->initialize();
}
T* ptr = reinterpret_cast<T*>(&this->aligned_data[i].data);
return *ptr;
}
};
And then use it like this
UninitializedArray<Something, 5> arr;
arr[0].do_something();
If you ever get C++17 working, then you can use std::array and std::optional to make this easy
std::optional<std::array<T, N>> optional_array;
// construct the optional, this will construct all your elements
optional_array.emplace();
// then use the value in the optional by "treating" the optional like
// a pointer
optional_array->at(0); // returns the 0th object

Wrap existing memory with const std::vector?

OK, so I recently learned that (a) std::vector uses contiguous memory by definition/standard, and thus (b) &(v[0]) is the address of that contiguous block of memory, which you can read/write to as an old-skool C-array. Like...
void printem(size_t n, int* iary)
{ for (size_t i=0; i<n; ++i) std::cout << iary[i] << std::endl; }
void doublem(size_t n, int* iary)
{ for (size_t i=0; i<n; ++i) iary[i] *= 2; }
std::vector<int> v;
for (size_t i=0; i<100; ++i) v.push_back(i);
int* iptr = &(v[0]);
doublem(v.size(), iptr);
printem(v.size(), iptr);
OK, so that's cool, but I want to go in the other direction. I have lots and lots of existing code like
double computeSomething(const std::vector<SomeClass>& v) { ... }
If I have a C-array of objects, I can use such code like this:
SomeClass cary[100]; // 100*sizeof(SomeClass)
// populate this however
std::vector<SomeClass> v;
for (size_t i=0; i<100; ++i) v.push_back(cary[i]);
// now v is also using 100*sizeof(SomeClass)
double x = computeSomething(v);
I would like to do that (a) without the extra space and (b) without the extra time of inserting a redundant copy of all that data into the vector. Note that "just change your stupid computeSomething, idiot" is not sufficient, because there are thousands of such functions/methods that exhibit this pattern that are not under my control and, even if they were are too many to go and change all of them.
Note also that because I am only interested in const std::vector& usage, there is no worry that my original memory will ever need to be resized, or even modified. I would want something like a const std::vector constructor, but I don't know if the language even allows special constructors for const instances of a class, like:
namespace std { template <typename T> class vector {
vector() { ... }
vector(size_t n) { ... }
vector(size_t n, const T& t) { ... }
const vector(size_t n, T*) { ... } // can this be done?
...
If that is not possible, how about a container derived off of std::vector called std::const_vector, which (a) could construct from a pointer to a c-array and a size, and (b) purposefully did not implement non-const methods (push_back, resize, etc.), so then even if the object with a typename of const_vector is not actually a const object, the interface which only offers const methods makes it practically const (and any erroneous attempts to modify would be caught at compile time)?
UPDATE: A little messing around shows that this "solves" my problem wrt Windows-implementation of std::vector:
template <typename T>
class vector_tweaker : public std::vector<T> {
public:
vector_tweaker(size_t n, T* t) {
_saveMyfirst = _Myfirst;
_saveMylast = _Mylast;
_saveMyend = _Myend;
_Myfirst = t;
_Mylast = t + n;
_Myend = t + n;
}
~vector_tweaker() {
_Myfirst = _saveMyfirst;
_Mylast = _saveMylast;
_Myend = _saveMyend; // and proceed to std::vector destructor
}
private:
T* _saveMyfirst;
T* _saveMylast;
T* _saveMyend;
};
But of course that "solution" is hideous because (a) it offers no protection against the base class deleting the original memory by doing a resize() or push_back() (except for a careful user that only constructs const vector_tweaker()) -- and (b) it is specific to a particular implementation of std::vector, and would have to be reimplemented for others -- if indeed other platforms only declare their std::vector member data as protected: as microsoft did (seems a Bad Idea).
You can try reference-logic storing introduced in C++11 with std::reference_wrapper<>:
SomeClass cary[100];
// ...
std::vector<std::reference_wrapper<SomeClass>> cv;
cv.push_back(cary[i]); // no object copying is done, reference wrapper is stored
Or without C11, you can create a specialization of such template class for bytes - char. Then for the constructor from char* C-array you can use ::memcpy: which unfortunately will then use twice as much memory.
::memcpy(&v[0], c_arr, n);
Something like this:
template <typename T> class MyVector : public std::vector<T> {
};
template <> class MyVector<char> : public std::vector<char> {
public:
MyVector<char>(char* carr, size_t n) : std::vector<char>(n) {
::memcpy(&operator[](0), carr, n);
}
};
What I would recommend - replace all C-arrays to vectors where possible, then no extra copying will be needed.

where does STL vector keeps data items of varying size?

Specifically, how does STL align vector items in vector< vector< T > > , given that each of the vector items may change size? Does the outer vector aligns references and keeps the items elsewhere?
A std::vector holds a pointer to the first element of array. When the number of elements change and the array needs to grow or shrink a new array is allocated and the data is copied. The actual size of the vector object itself never changes.
The vectors typically don't "change size". In general, the storage of the vector is implemented using a pointer-to-T member variable. (And it's only the memory pointed to by that pointer that's reallocated upon resizing, and naturally, that doesn't change the size of the vector instance itself.)
Standard vector is fundamentally a wrapper around this
template<typename T>
class vector
{
T* m_data;
size_t m_count;
size_t m_capacity;
//...
void push_back(const T& src) {
if (m_capacity < m_count + 1) {
size_t newCapacity = m_capacity + growthRate();
T* newData = ::realloc(m_data, newCapacity);
// ...
m_data = newData;
m_capacity = newCapacity;
}
// copy into the slot at m_count
m_data[m_count] = src;
++m_count;
}
};
As such, a given instance of a vector always stores the same size of element. The only way it can contain polymorphic or variable items is via pointers, e.g.
class Base {};
class D1 : public Base {};
class D2 : public Base { int i; };
std::vector<std::unique_ptr<Base>> vec;
vec.emplace_back(new Base);
vec.emplace_back(new D1);
vec.emplace_back(new D2);