how to work with deleted object on custom vector - c++

I know that std vectors can work with objects that are not default constructible. However, when I try to implement a slightly modified one myself, I cant seem to make such vector.
class A
{
public:
A() = delete;
A(const int &x)
:x(x)
{}
private:
int x;
};
template <typename T, int N> //default constructor of the vector
CircularBuffer<T,N>::CircularBuffer()
{
Size = 0;
Capacity =N;
Array = new T[Capacity];
Start = 0;
End = 0;
}
template <typename T, int N>
CircularBuffer<T,N>::CircularBuffer(const CircularBuffer& rhs) //copy constructor of the vector
{
Size = rhs.Size;
Capacity = rhs.Capacity;
Array = new T[Capacity];
Start = rhs.Start;
End = rhs.End;
for(int i=0;i<Capacity;i++)
{
this->Array[i] = rhs.Array[i];
}
}
template <typename T, int N> //move constructor of the vector
CircularBuffer<T,N>::CircularBuffer(CircularBuffer&& rhs)
{
rhs.Swap(*this);
}
template <typename T, int N>
void CircularBuffer<T,N>:: Swap(CircularBuffer &source)
{
swap(Size,source.Size);
swap(Capacity,source.Capacity);
swap(Start,source.Start);
swap(End,source.End);
swap(Array,source.Array);
}
When I try to make a vector with object A,
CircularBuffer<A,3> v;
error: use of deleted function ‘A::A()’
I get this error which is obviously self explanatory. Anyone can help me solve this??

The problem is here
Array = new T[Capacity];
which default constructs T objects.
std::vector uses placement new to construct objects when they are added to the vector.
Array = (T*)operator new(sizeof(T)*Capacity);
and (when you add the new item)
new(Array + i) T(...); // placement new
where ... are the arguments you wish to pass to the constructor.
See here for more details.

The issue is with the line Array = new T[Capacity];. This needs to default-initialize all members of the array, which it cannot do without a default-constructor.
std::vector gets around it by splitting allocation and construction with its allocator. I recommend you simply use std::allocator as well. Otherwise you can use placement-new to construct the elements after allocating the required memory separately.

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.

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

Adding something to an array

I have a class, whereby one of its elements is of another class, but is an array
class B
{
public:
B() //default
{
element = new A [1]; count = 0;
}
A add(A place)
{
A* newArr;
newArr = new A [count+1];
newArr = element;
newArr[count+1] = place;
delete element;
return newArr[count+1];
}
protected:
int count;
A* element;
};
I am trying to use dynamic arrays, where I when adding the element, I make a new array dynamically, initilzed to the size of the old array plus 1, then copy the elements of the old array to the new array, and then delete the old array. But I am unsure of how to modify the array that's already within the class, if that makes sense (Basically what to return in my add method).
In C++ there's no notion of resizing arrays once declared. Same goes for dynamic arrays, which can't be resized once allocated. You can, however, create a bigger sized array, copy all elements from the older array to the newer one and delete the old one. This is discouraged and would not be performant.
Using std::vector would allow you to add at will and will also keep track of its size, so you don't need count as part of the class.
class B
{
// no need to allocate, do add when required i.e. in B::add
B() : count(), elements() { }
A add(A place)
{
// unnecessarily allocate space again
A *new_elements = new A[count + 1];
// do the expensive copy of all the elements
std::copy(elements + 0, elements + count, new_elements);
// put the new, last element in
new_elements[count + 1] = place;
// delete the old array and put the new one in the member pointer
delete [] elements;
elements = new_elements;
// bunp the counter
++count;
return place; //redundant; since it was already passed in by the caller, there's no use in return the same back
}
protected:
size_t count;
A *elements;
};
The above code perhaps does what you want but is highly discouraged. Use a vector; you code will simply become
class B
{
// no need of a constructor since the default one given by the compiler will do, as vectors will get initialized properly by default
void Add(A place)
{
elements.push_back(place);
// if you need the count
const size_t count = elements.size();
// do stuff with count here
}
protected:
std::vector<A> elements;
};
A more thorough example would be to more closely mimic std::vector:
template<typename T>
class B
{
private: // don't put data under a protected access!
std::size_t _capacity;
std::size_t _size;
T* _elements;
public:
B() : _capacity(0), _size(0), _elements(nullptr) {}
// other methods
void add(const T& t)
{
if (_size >= _capacity) // need to resize the array
{
_capacity++; // you can make this better by increasing by several at a time
T* temp = new T[_capacity];
std::copy(_elements, _elements + _size, temp);
delete [] _elements;
_elements = temp;
}
_elements[_size++] = t;
}
};

Initialising nested templates

I'm trying to learn more about templates and have come across a problem I can't seem to solve. At the moment the class below works fine.
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
template <class T, int s>
class myArray{
public:
T* data;
inline T& operator[](const int i){return data[i];}
myArray(){
data=new T[s];
}
myArray(const myArray& other){
data=new T[s];
copy(other.data,other.data+s,data);
}
myArray& operator=(const myArray& other){
data=new T[s];
copy(other.data,other.data+s,data);
return *this;
}
~myArray(){delete [] data;}
};
If I use it:
myArray<myArray<myArray<int,10>,20>,30> a;
a is now 30x20x10 array that I can access with the normal array brackets e.g. a[5][5][5]. I wish to add a feature so that I could write:
myArray<myArray<myArray<int,10>,20>,30> a(10);
and initialise all of the entries to 10 for example. I can't work out how to do this. As I understand, each layer of myArray is constructed using the default constructor. If I changed this to something like:
myArray(int n=0){
data=new T[s];
fill(data,data+s,n); //T might not be of type int so this could fail.
}
I think this should fail when data is not of type int (i.e. on any array on dimensions > 1), however it doesn't. It works when the array is square, but if not then some of the entries aren't set to 10. Does anyone have an idea how the standard vectors class achieves this? Any help would be amazing. Thanks!
Well, try something like this:
myArray()
: data(new T[s]()) // value-initialization!
{
}
myArray(T const & val)
: data(new T[s]) // default-initialization suffices
{
std::fill(data, data + s, val);
}
If you're into variadic templates, you might cook up something even more grotesque involving variadically filled initializer lists, but I think we've done enough learning for one week.
Note the fundamental flaw in using new: Either version requires that your class T can be instantiated in some "default" state, and that it be assignable, even though we never require the default state in the second version. That's why "real" libraries separate memory allocation and object construction, and you never see a new expression unless its the placement version.
std::vector uses placement new on memory blocks. It constructs the data.after allocating the memory in a second line of code.
This technique would work for you as well. Be careful with placement new as it requires you to call destructors manually as well.
Here is a half-assed route without placement new:
template<typename U>
explicit MyArray( U const& constructFromAnythingElse )
{
AllocateSpace(N); // write this, just allocates space
for (int i = 0; i < N; ++i)
{
Element(i) = T( constructFromAnythingElse );
}
}
with placement new, you have to allocate the memory first, then construct in-place, and then remember to destroy each element at the end.
The above is half-assed compared to a placement new route, because we first construct each element, then build another one, and use operator= to overwrite it.
By making it a template constructor on an arbitrary type, we don't rely on multiple conversion to get multiple levels down into the array. The naive version (where you take a T const&) doesn't work because to construct an array of arrays of arrays of T, the outermost one expects an array of arrays of T as an argument, which expects an array of T as an argument, which expects a T -- there are too many levels of user defined construction going on there.
With the above template constructor, the array of array of array of T accepts any type as a constructor. As does the array of array of T, as does the array of T. Finally, the T is passed in whatever you constructed the outermost array of array of array of T, and if it doesn't like it, you get a compiler error message that is nearly completely unreadable.
Make specialization for arrays containing other arrays. To do this you need some common implementation class to be used in general and specialized MyArray:
Common implementation (I made some fixes for you - see !!! comments):
template <class T, int s>
class myArrayImpl {
public:
T* data;
T& operator[](int i){return data[i];} //!!! const before int not needed
const T& operator[](int i) const {return data[i];} //!!! was missing
myArrayImpl(){
data=new T[s]();
}
myArrayImpl(const myArrayImpl & other){
data=new T[s];
copy(other.data,other.data+s,data);
}
myArrayImpl& operator=(const myArrayImpl& other){
T* olddata = data; // !!! need to store old data
data=new T[s];
copy(other.data,other.data+s,data);
delete [] olddata; //!!! to delete it after copying
return *this;
}
~myArrayImpl(){delete [] data;}
};
Then make general implementation - note the definition of value_type and setAll:
template <class T, int s>
class myArray : private myArrayImpl<T,s> {
typedef myArrayImpl<T,s> Impl;
public:
using Impl::operator[];
myArray() : Impl() {}
typedef T value_type; // !!!
explicit myArray(const value_type& value) {
setAll(value);
}
void setAll(const value_type& value) {
fill(this->data, this->data + s, value);
}
};
And the specialized version for myArray of myArray - see also differences in value_type and setAll:
template <class T, int s1, int s2>
class myArray<myArray<T,s2>,s1> : private myArrayImpl<myArray<T,s2>,s1> {
typedef myArrayImpl<myArray<T,s2>,s1> Impl;
public:
using Impl::operator[];
myArray() : Impl() {}
typedef typename myArray<T,s2>::value_type value_type; // !!!
explicit myArray(const value_type& value) {
setAll(value);
}
void setAll(const value_type& value) {
for_each(this->data, this->data + s1, [value](myArray<T,s2>& v) { v.setAll(value); });
}
};
And usage:
int main() {
myArray<myArray<myArray<int,7>,8>,9> a(7);
std::cout << a[0][0][0] << std::endl;
std::cout << a[8][7][6] << std::endl;
}
Full example here: http://ideone.com/0wdT9D

Templates delete in C++ when List<List<X>>

I am trying to develop a generic List with templates. This list is compound by a Pointer array T* , an integer for getting the number of elements and some methods( find, contains...) It´s important to say that I cannot use std::library.
My problem comes when I am working with a List<List<int> > for instance.
One of the methods make a resizing of the T* pointer array, So when I have this List<List>>I create an auxpointer of a bigger size than T* and copying T content to auxpointer with a memcpy. The inner Pointers (list.T.T) are copied as pointers too, not memory duplicated, so when I delete the T* pointer and reasign T=auxpointer. I have already lost the data of that pointers in my new T.
template <typename T>
void CGenericList<T>::resize()
{
T* auxPointer = new T[this->maxElements*2];
memcpy (auxPointer,this->pointer,this->maxElements*sizeof(T));
delete[] this->pointer;
this->pointer=auxPointer;
this->maxElements=2*this->maxElements;
}
template<class T>
class CGenericList
{
public:
T* pointer;
int N;
int maxElements;
CGenericList();
CGenericList(int);
~CGenericList();
void resize();
}
Can anyone give me any tips for doing it?
The code you posted shows some problems.
T* auxPointer = new T[this->maxElements*2];
here you allocate a new array of maxElements*2 - and call the default constructor.
Which in your case probably initialises all Listelements.
memcpy (auxPointer,this->pointer,this->maxElements*sizeof(T));
After that you copy the content of your old array to the memory area of the newly allocated memory. This overwrites the pointers to the just created Listelements with the ones from the old array -> memory leak.
delete[] this->pointer;
Then you delete the array, this calls the destructors of all elements.
Which hopefully will delete their content and free their memory.
this->pointer=auxPointer;
Finally you reassign the newly created array. The pointers in the list point to the old listselements and point to not allocated memory anymore (because of the call to the destructor via delete[]).
A solution would be to implement an copy constructor for your list and call it for all
elements in your array. (DeepCopy) And of course an assignment operator, i almost forgot ;)
CGenericList(const CGenericList<T>& copy);
CGenericList<T>& operator= (const CGenericList<T>& rhs)
Probably somethig like this - be aware that this is "asis" and definitely not exceptionsafe ;)
template<class T>
class CGenericList
{
public:
T* pointer;
int N;
int maxElements;
CGenericList();
CGenericList( const CGenericList<T>& copy );
CGenericList<T>& operator=(const CGenericList<T>& rhs);
CGenericList(int);
~CGenericList();
void resize();
};
template <typename T>
void CGenericList<T>::resize()
{
T* auxPointer = new T[this->maxElements*2];
for(int i=0; i < this->maxElements; i++)
{
auxPointer[i] = this->pointer[i];
}
delete[] this->pointer;
this->pointer = auxPointer;
this->maxElements = this->maxElements*2;
}
template <typename T>
CGenericList<T>::CGenericList()
:N(0)
,maxElements(0)
{
this->pointer = new T[1];
}
template <typename T>
CGenericList<T>::CGenericList(const CGenericList<T>& copy)
:N(copy.N)
,maxElements(copy.maxElements)
{
T* temp = new T[copy.maxElements];
for(int i=0; i<N; i++ )
{
temp[i] = copy.pointer[i];
}
this->pointer = temp;
}
template <typename T>
CGenericList<T>& CGenericList<T>::operator=(const CGenericList<T>& rhs)
{
if( this != &rhs )
{
delete[] this->pointer;
this->pointer = new T[rhs.maxElements];
for(int i=0; i<rhs.maxElements; i++)
{
this->pointer[i] = rhs.pointer[i];
}
}
return *this;
}
template <typename T>
CGenericList<T>::CGenericList(int size)
:N(0)
,maxElements(size)
{
this->pointer = new T[size];
}
template <typename T>
CGenericList<T>::~CGenericList()
{
delete[] this->pointer;
}
int main(int /*argc*/, char */*argv*/[])
{
CGenericList<CGenericList<int> > list;
list.resize();
return 0;
}
If you don't like to use stl you can have a look at stlport
Your resize is not exception safe. You are first deleting the existing array and then allocating memory for a different size and then assigning auxPointer.
Coming to the problem you are having, check if the below approach helps.
T* auxPointer = new T[this->maxElements*2];
for ( int i =0; i < this->maxElements; ++i)
std::swap(auxPointer[i], pointer[i]);
delete[] this->pointer;
this->pointer = auxPointer;
this->maxElements=2*this->maxElements;