How to implement copy operator for such C++ structure? - c++

So having
struct ResultStructure
{
ResultStructure(const ResultStructure& other)
{
// copy code in here ? using memcpy ? how???
}
ResultStructure& operator=(const ResultStructure& other)
{
if (this != &other) {
// copy code in here ?
}
return *this
}
int length;
char* ptr;
};
How to implement "copy constructor" and "assignment operator"? (sorry - I am C++ nube)
Update: sbi and others ask - why do I want to manually deal with raw memory? My answer is simple - In a students project I am part of now we use lots of C library's such as for example OpenCV OpenAL and FFmpeg and there are more to come. Currently using C++ we try to create a graph based direct show like cross platform library that would be helpful in live video broadcasting and processing. Our graph elements currently use char* and int pairs for data exchange. To cast data to subscribed elements we use raw memcpy now. I want to go further and make it possible for us to make our graph elements base C++ template. So that one graph element would be capable of of sharing current graph element data with other Graph elements and that data it shares would be a structure that would contain not one char* one int but any number of data fields and nearly any elements inside. So that is why I need to understand how to create a basic C++ structure that implements "copy constructor" and "assignment operator" for me to be capable to use new for us data casting algorithms like
void CastData(T item){
for(size_t i = 0 ; i < FuncVec.size(); i++){
T dataCopy = item;
FuncVec[i](dataCopy);
}
}
instead of currently used
void CastData(char * data, int length){
for(size_t i = 0 ; i < FuncVec.size(); i++){
char* dataCopy = new char[length];
memcpy(dataCopy, data, length);
FuncVec[i](dataCopy, length);
delete[] dataCopy;
}
}

You might want to explain why you want to manually deal with raw memory. I haven't done this in a long time, it's what std::string and std::vector where designed for:
struct ResultStructure
{
// nothing else needed
std::string data; // or std::vector<char>
};
But if you really need to do this the hard way (is this homework?), then be advised that it is, at first, surprisingly hard to get this right. For example, a naive implementation of the assignment operator might be like this:
// DON'T TRY THIS AT HOME!!
ResultStructure& ResultStructure::operator=(const ResultStructure& rhs)
{
delete[] ptr; // free old ressource
ptr = new char[rhs.length]; // allocate new resourse
std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr; // copy data
length = rhs.length;
}
If someone accidentally assigns an object to itself (which might happen if all you have is two references and you don't suspect them to refer to the same object), then this will fail fatally.
Also, what if new throws an exception? (It might throw std::bad_alloc if memory is exhausted.) Then we have already deleted the old data and have not allocated new data. The pointer, however, still points at where the old data used to be (actually, I think this is implementation-defined, but I have yet to see an implementation that changes a ptr upon deletion), and the class' destructor (you knew that class would need a destructor, right?) would then attempt to delete a piece of data at an address where no data is allocated. That's Undefined Behavior. The best you can hope for is that it crashes immediately.
The easiest way to do this is to employ the Copy-And-Swap idiom:
struct ResultStructure
{
ResultStructure(const ResultStructure& other)
: ptr(new char[rhs.length]), length(rhs.length)
{
std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr);
}
~ResultStructure() // your class needs this
{
delete[] ptr;
}
ResultStructure& operator=(ResultStructure rhs) // note: passed by copy
{
this->swap(rhs);
return *this
}
void swap(const ResultStruct& rhs)
{
using std::swap;
swap(length, rhs.length);
swap(ptr, rhs.ptr);
}
std::size_t length;
char* ptr;
};
Note that I have added a destructor, changed the assignment operator to pass the argument per copy (we need the copy constructor invoked to allocate memory), and added a swap member function. Per convention a swap() function never throws and is fast, preferably O(1).
I know that GMan's discussion of the Copy-And-Swap idiom is exhaustive enough to be and exhausting while mine is probably too terse for you, and you will likely not understand a lot of it at first, but try to persevere and to understand as much as possible.

If you use std::string, instead of char*, you would not even need to write operator= or copy-constructor. The compiler generated code would do your job very well.
But as a general solution (for some other scenario), use copy-and-swap idiom:
Copy-and-Swap Idiom
What is the copy-and-swap idiom?
Exceptional C++ by Herb Sutter has described these in great detail. I would recommend you to read items from this book. For the time being, you can read this article online:
Exception-Safe Generic Containers

The easy solution is to use a std::string instead of char* member.
Then the compiler-generated copy constructor and copy assignment operator just work.
As a rule, and especially as a novice, don't have raw pointer members.
Cheers & hth.,

As has been said, and as was recommending in the question this emanated from, you should probably reuse an existing container. At least the code would be right :)
For educational purposes though, let's examine this structure:
class Result
{
public:
private:
size_t length; // can't really be negative, right ?
char* data;
};
Here, we need explicit memory management. This implies, notably, following the Rule Of Three (say thanks to Fred)
Let's begin with actually building our object:
Result::Result(): length(0), data(0) {}
Result::Result(size_t l, char* d): length(0), data(0)
{
if (!d) { return; }
data = new char[l]; // this may throw, so we do it first
length = l;
memcpy(data, d, l);
}
Now we can implement the traditional operators:
// Swap
void Result::swap(Result& other)
{
using std::swap;
swap(length, other.length);
swap(data, other.data);
}
// Copy Constructor
Result::Result(Result const& other): length(0), data(0)
{
if (!other.length) { return; }
data = new char[other.length];
length = other.length;
mempcy(data, other.data, length);
}
// Assignemt Operator
Result& Result::operator=(Result other)
{
this->swap(other);
return *this;
}
// !IMPORTANT!
// Destructor
Result::~Result()
{
delete[] data; // use the array form of delete
// no need to test for nullity, it's handled
}

this is std::vector<char>'s job - or is this homework?
the vector would replace both length and the allocation behind ptr. the vector is the c++ idiom, and you'll not make friends with other c++ devs if you implement your classes like you've described. of course, there are corner cases, but standard containers such as vector are the default.
the vector knows how to copy chars as well as itself, and the implementations are optimized and tested.
here's how to explicitly implement copy ctor/assign using a vector:
struct ResultStructure {
ResultStructure(const ResultStructure& other) : d_chars(other.d_chars) {
}
ResultStructure& operator=(const ResultStructure& other) {
if (this != &other) {
this->d_chars = other.d_chars;
}
return *this;
}
std::vector<char> d_chars;
};

I think this should do the work:
struct ResultStructure
{
ResultStructure(const ResultStructure& other);
ResultStructure& operator=(const ResultStructure& other);
int length;
char* ptr;
};
ResultStructure::ResultStructure(const ResultStructure& other):length(other.length)
{
ptr = (char*)malloc(length);
memcpy(ptr, other.ptr, length);
}
ResultStructure& ResultStructure::operator=(const ResultStructure& other)
{
length = other.length;
ptr = (char*)malloc(length);
memcpy(ptr, other.ptr, length);
return *this;
}
Please remember about freeing ptr in destructor.
What is stored under ptr? If text, why not to use std::string? Anyway you can use std::vector. The constructors will be much easier then...

How is the memory to which ptr points allocated?
if using new, allocate with new, set length and then copy
other.length = length;
other.ptr = new char[length];
memcpy( other.ptr, ptr, length );
If you're allocating the memory with malloc, substitute a call to malloc in place of the call to new. If you're using some other memory scheme, figure it out. :)

Related

Destructor deleting memory premature

I am quiet new to memory management in C++. I made a BigInt class that is now fully implemented except for the destructor which is impacting performance of the program. However, when I try to implement the destructor my program crashes.
In the following code for multiplying BigInts:
BigInt& BigInt::operator*=(BigInt const& other) {
//copy of this and other
BigInt* tempThis = new BigInt(*this); //1st number
BigInt* tempOther = new BigInt(other); //2nd number
//create temps so we can use value of BigInt before it is changed
BigInt* sum = new BigInt(0); //holds the eventual answer
BigInt* i = new BigInt(0);
//add *this BigInt to sum otherTemp amount of times
//this will yield multiplication answer.
for (*i; *i < *tempOther; *i = *i + 1) {
*sum += *this;
}
*this = *sum;
return *this;
}
The destructor is called when *i = *i + 1 is called in the for loop and then I think it gets deleted in my destructor which looks like this:
// destructor
BigInt::~BigInt() {
delete[] this->bigIntVector;
}
// copy constructor
BigInt::BigInt(BigInt const& orig)
: isPositive(orig.isPositive)
, base(orig.base)
{
this->bigIntVector = new BigIntVector(*(orig.bigIntVector));
}
Once 'i' is deleted nothing works and the whole program breaks.
If someone could give me a few pointers about destructors and how to fix my problem it would be great help. Thanks.
In C++, the same (horrible) arithmetic could be implemented as follows.
BigInt& BigInt::operator*=(BigInt const& other)
{
if(other==0)
return other;
if(other> 1)
for(BigInt old=*this,i=1; i!=other; ++i)
operator+=old;
else if(other<0) {
BigInt old=*this;
*this=0;
for(BigInt i=0; i!=other; --i)
operator-=old;
}
return*this;
}
assuming that the constructor from int, the copy constructor, the increment operator++ and the addition operator+= are all properly implemented (as well as the destructor).
Unfortunately, you failed to give us more information, but your copy constructor and destructor are definitely broken:
this->bigIntVector = new BigIntVector(*(orig.bigIntVector));
is followed by
delete[] this->bigIntVector;
giving you undefined behaviour (allocating with new but deallocating with delete[] -- delete[] is for memory allocated with new[]). I suspect you meant to copy the memory from the original in the copy constructor. However, you don't. If
class BigInt {
size_t size=0; // number of some_types allocated
some_type*bigIntVector=nullptr; // ptr to memory allocated, if any
/* rest of class */
};
then the copy constructor could be implemented like (assuming size is non-static)
BigInt::BigInt(BigInt const&orig)
: size(orig.size() // copy size
, bigIntVector(size? new some_type[size] : nullptr) // allocate memory
{ std::memcpy(orig.bigIntVector, bigIntVector); } // copy memory
However, (almost) the same could be implemented much easier with
class BigInt
{
std::vector<some_type> bigIntVector;
public:
BigInt(BigInt const&) = default;
BigInt(BigInt &&) = default;
BigInt&operator=(BigInt const&) = default;
BigInt&operator=(BigInt &&) = default;
/ * rest of class */
};
when the copy and move constructors (as well as the respective assignment operators) are automatically correctly created for you. You only need to address the default constructor, for example
BigInt::BigInt() // default constructor
: bigIntVector(1,some_type(0)) {} // size=1, value=0
and the constructors from built-in integer types. If you're new to C++, avoid new and delete in favour of standard library containers.

C++ Assignment overload self-assignment issue

I am currently working on an ADT called Text and I'm overloading the assignment operator. When I test the operator like so: assignText = alpha everything outputs okay. However, when I do assignText = assignText then two solid bars output instead.
assignText is declared as a Text object.
My overloaded assignment operator is as follows:
void Text::operator= (const Text& other) {
bufferSize = other.getLength();
buffer = new char[bufferSize];
buffer = other.buffer;
}
Where int bufferSize and char *buffer
Any tips or suggestions would be greatly appreciated. If anything else is needed, just let me know.
Other answers already have pointed out various issues with your operator implementation. Here I'll try to understand what's happening for you, i.e. why the code behaves as you observe. If this == &other, i.e. during self assignment, you take the current length as the size of a new buffer. That new buffer isn't initialized, so at that point it might contain random bytes. The last assignment is a no-op in case of a self-assigment. To sum things up:
void Text::operator= (const Text& other) {
bufferSize = other.getLength(); // Take length from current object
buffer = new char[bufferSize]; // Create new buffer, old buffer turns into a memory leak
buffer = other.buffer; // No-op as both are the same variable
}
So what this tells you is that you end up with a buffer of the current object size but with undefined content. In your case that undefined content happens to represent the vertical bars you mention.
To solve this, make sure to fix the assignment operator based on the suggestions from other answers and comments.
This is a memory leak. You're assigning two different pointers to buffer.
buffer = new char[bufferSize];
buffer = other.buffer;
Regarding the problem at hand, that's covered by the C++ FAQ: "Why should I worry about "self assignment"?". It's often a good idea to read the FAQ first. Or at least skim it.
When you absolutely have to implement a copy assignment operator, usually the copy-and-swap idiom will be good enough. It's also exception safe. Goes like this:
void swapWith( MyType& other ) throw()
{
// swap them members
}
void operator=( MyType other )
{
swapWith( other );
}
Here the copy constructor creates the formal argument copy, and any exception happens there, so that the copy constructor centralizes also the cleanup in case of copy failure. After that the contents of the two objects are swapped, and the copy object's destructor takes care of cleaning up what was this object's internal stuff. The void result type is not yet conventional, but as I see it it's not smart to waste both code and time on supporting expressions with side effects, which are evil.
Now, you can avoid all this, simply by using std::vector for your buffer.
So that's what I recommend, the really simple solution: use std::vector.
This is because your assignment operator is fundamentally unsafe. You need to break the old state as the last step. Consider
Text& Text::operator= (const Text& other) {
auto new_buffer = new char[other.bufferSize];
std::copy(other.buffer, other.buffer + other.bufferSize, new_buffer);
// Now consider whether or not you need to deallocate the old buffer.
// Then set the new buffer.
buffer = new_buffer;
bufferSize = other.bufferSize;
return *this;
}
This ensures that if any problems are encountered, it is guaranteed that the Text object is always valid- and as a bonus, is self-assignment-safe. All well-written assignment operators are self-assignment safe.
This is often tied with copy-and-swap, which copies, then swaps- guaranteeing safety.
This piece of code will work perfectly
Text& Text::operator=(const Text& other)
{
if(this == &other) /* checks for self assignment */
return *this;
if(NULL == other.buffer)
return *this;
if(NULL != buffer) /* assuming buffer=NULL in constructor */
{
delete [] buffer;
buffer = NULL;
}
bufferSize = other.getLength();
buffer = new char[bufferSize+1];
memset(buffer, 0, bufferSize+1);
memcpy(buffer, other.buffer, bufferSize);
return *this;
}
Try this..
After some thought and review, I think I got it. Given that I need to write a void function dictated by the header file that I must construct my implementation from. I took into consideration the comments from Drew Dormann, MvG, as well as others and came up with this:
void Text::operator= (const Text &other)
{
if (this != &other) // takes care of self-assignment
{
delete [] buffer; // delete the old buffer
bufferSize = other.bufferSize; // assign size variable
buffer = new char[bufferSize + 1]; // create new buffer
strcpy(buffer, other.buffer); // copy array
}
}
This works and I believe it is memory leak free.

compact vector a small memory foot print vector

I maintain a old C++ application which has a lot of classes like below:
class ClassWithALotOfVectors
{
std::vector<int> _vector1;
std::vector<int> _vector2;
// a lot of other vector datamembers go here
std::vector<double> _vectorN;
};
that is - a data type where members a vectors of double or int.
The thing is - these vectors are never populated at the same time - and therefore
when we create 100000 instances of ClassWithALotOfVectors - memory usage adds up
to impressive number even though only 10% of these vector are in use.
So I decided to write a small "allocate on demand" vector class.
It is a wrapper around std::vector - where internal vector only create when
accessed for the first time (using two getters - ref() & const_ref() methods)
When I replaced std::vector in a ClassWithALotOfVectors class with a compact_vector
as below:
class ClassWithALotOfVectors2
{
compact_vector<int> _vector1;
compact_vector<int> _vector2;
compact_vector<double> _vectorN;
};
did a few tests and the results were promising - memory usage went down
dramatically, but suddenly found that application does not release memory
at the end - the memory consumptions grows in much slower rate than it
is used to be - but application does not seem to be deallocating the memory
at the end.
Can you look at my implementation of the compact_vector
and see if you can spot something wrong with a memory management.
template <class T> class compact_vector
{
public:
compact_vector<T>()
:_data(NULL)
{
}
~compact_vector<T>()
{
clear();
}
compact_vector<T>(const compact_vector<T> & rhs)
:_data(NULL)
{
if (NULL != rhs._data)
{
_data = new std::vector<T>(*(rhs._data));
}
else
{
clear();
}
}
// assignment
//
compact_vector<T> & operator=(const compact_vector<T> & rhs)
{
if (this != &rhs)
{
clear();
if (NULL != rhs._data)
{
_data = new std::vector<T>(*rhs._data);
}
}
return *this;
}
compact_vector<T> & operator=(const std::vector<T> & rhs)
{
clear();
if (!rhs.empty())
{
_data = new std::vector<T>(rhs);
}
return *this;
}
const std::vector<T> & const_ref()
{
createInternal();
return *_data;
}
std::vector<T> & ref()
{
createInternal();
return *_data;
}
void clear()
{
if (NULL != _data)
{
_data->clear();
delete _data;
_data = NULL;
}
}
private:
void createInternal()
{
if (NULL == _data)
{
_data = new std::vector<T>();
}
}
private:
compact_vector<T>(const std::vector<T> & rhs)
{
}
compact_vector<T>(std::vector<T> & rhs)
{
}
compact_vector<T>(std::vector<T> rhs)
{
}
std::vector<T> * _data;
};
Most implementations of std::vector don't acquire memory until you need it, and the size of a vector is usually just a few (3 + possibly extra debug information) pointers. That is, std::vector<int>() will not allocate space for any object. I believe that you are barking at the wrong tree here.
Why is your original code having a much higher memory usage? Are you expecting clear() to release memory?
If so you are mistaken. The clear() function destroys the contained elements but does not release the allocated memory. Consider adding a wrapper to clear the memory that uses the following idiom:
std::vector<int>().swap( _data );
What the previous line does is creating a new empty vector (usually no memory attached, not mandated, but common implementation) and swapping the contents of the two vectors. At the end of the expression, the temporary contains the data that was originally held by the _data vector and _data is empty and with no memory (implementation defined). The temporary is destructed at the end of the full expression and memory is released.
Alternatively, if your compiler supports C++11, you can use shrink_to_fit() after calling clear(). The standard does not require shrink_to_fit() to actually shrink to fit, but for an empty vector I would expect the implementation to do it. Test it by calling capacity() after the call and seeing whether it has gone down to 0 or not.
Use smart pointers. In this case, std::unique_ptr with hand-made copy ctor / assignment operator. Suddenly, all your problems are solved. It's like magic!
Sorry to sound so snarky, but memory leaks always have the same answer: smart pointer.
Since you are saying it's an old application and can't do much with it. How about having all the vectors having zero size reserved during construction.
It's tedious, but since old app and not much is expected to be modified. May be worth the effort for once.
class ClassWithALotOfVectors
{
std::vector<int> _vector1;
std::vector<int> _vector2;
// a lot of other vector datamembers go here
std::vector<double> _vectorN;
public:
ClassWithALotOfVectors() : Init() { }
void Init()
{
vector1.reserve(0);
/// Like wise other vectors.
}
};
The idea that only one vector at a time is ever in use sounds like the union concept. Sure enough, C++ has an element called an anonymous union that does precisely this.
class ClassWithALotOfVectors {
public:
union {
std::vector<double> _vector1;
std::vector<double> _vector2;
};
ClassWithALotOfVectors() { new(&_vector1) std::vector<double>; };
~ClassWithALotOfVectors() { _vector1.~vector<double>(); };
};
Because the union can't know which element's constructor to call, default constructors are disabled in the union and you have to manually construct and deconstruct the union's element, but I think this will accomplish what you are looking for, aliasing _vector1 and _vector2 to the same element but placing both in the ClassWithALotOfVectors namespace, then deallocating the vector when the destructor for ClassWithALotOfVectors is called.
For more on anonymous unions see:
CPP reference: Anonymous Unions

C++ helper function for copy constructor

I haven't been able to find a good answer to this question.
I'm working on a C++ program and I'm trying to implement a function named copy which takes a reference to another object as an argument. Then, it returns a deep copy of this object.
Some background on my project: the Scene class contains a dynamic array (called "Images") of pointers to either NULL or an instance of the Image class, which is not shown here - but works as it should (it inherits all of its methods from a third party library, EasyBMP)
The reason I'm doing this is to avoid duplicating code in two places, but it's very possible that I'm taking the wrong approach.
I call this function in my assignment operator:
Scene const & Scene::operator=(Scene const & source)
{
if (this != &source) {
clear();
copy(source);
}
return *this;
}
And my copy constructor:
Scene::Scene(Scene const & source)
{
copy(source);
}
Finally, my copy() method looks like this:
Scene const & Scene::copy(Scene const & source)
{
Scene res(source.Max);
for (int i=0; i<res.Max; i++)
{
delete res.Images[i];
if (source.Images[i] != NULL)
res.Images[i] = new Image(*(source.Images[i]));
else
res.Images[i] = NULL;
}
return res;
}
Currently, it does NOT work. One problem I can see is that I'm trying to return a variable that goes out of scope as soon as the copy function ends. I tried returning a reference before, but the compiler threw errors and this wouldn't help with the scope issue anyways.
But I'm not even sure that my logic is right, i.e. can you even do something like this in a constructor? Or should I just explicitly write out the code in the copy constructor and assignment operator (without implementing the helper method copy)?
I'm very new to C++ and pointers, so any guidance would be much appreciated.
There's a way easier and more idiomatic way to do what you want: the copy-and-swap idiom.
// N.B. Not tested, but shows the basic structure of the copy-and-swap idiom.
class Scene
{
public:
Scene(int)
{
// Initialize a pointer array of Images
}
~Scene()
{
// Get rid of our pointer array of Images
}
// Copy constructor
// N.B. Not exception safe!
Scene(const Scene& rhs) : imgPtrArray(new Image*[rhs.max])
{
// Perform deep copy of rhs
for (int i=0; i < rhs.max; ++i)
{
if (rhs.imgPtrArray[i] != 0)
imgPtrArray[i] = new Image(*(rhs.imgPtrArray[i]));
else
imgPtrArray[i] = 0;
}
}
// Copy assignment constructor
// When this is called, a temporary copy of Scene called rhs will be made.
// The above copy constructor will then be called. We then swap the
// members so that this Scene will have the copy and the temporary
// will destroy what we had.
Scene& operator=(Scene rhs)
{
swap(rhs);
return *this;
}
void swap(Scene& rhs)
{
// You can also use std::swap() on imgPtrArray
// and max.
Images** temp = imgPtrArray;
imgPtrArray = rhs.imgPtrArray;
rhs.imgPtrArray = temp;
int maxTemp = max;
max = rhs.max;
rhs.max = maxTemp;
}
private:
Images** imgPtrArray;
int max;
};
That being said, I highly recommend that you pick up a good introductory C++ book, which will cover the basics of implementing the copy constructor and copy assignment operators correctly.
Scene const & Scene::operator=(Scene const & source);
overloaded assignment operator copies the content of this to the argument received source. For copy there is no need to return any thing or to create a local object. Just make a member wise copy from this to source.
void Scene::copy(Scene const & source){
// Member wise copy from this to source
}
Rule of three should be helpful to better understand more about these.

How do you 'realloc' in C++?

How can I realloc in C++? It seems to be missing from the language - there is new and delete but not resize!
I need it because as my program reads more data, I need to reallocate the buffer to hold it. I don't think deleteing the old pointer and newing a new, bigger one, is the right option.
Use ::std::vector!
Type* t = (Type*)malloc(sizeof(Type)*n)
memset(t, 0, sizeof(Type)*m)
becomes
::std::vector<Type> t(n, 0);
Then
t = (Type*)realloc(t, sizeof(Type) * n2);
becomes
t.resize(n2);
If you want to pass pointer into function, instead of
Foo(t)
use
Foo(&t[0])
It is absolutely correct C++ code, because vector is a smart C-array.
The right option is probably to use a container that does the work for you, like std::vector.
new and delete cannot resize, because they allocate just enough memory to hold an object of the given type. The size of a given type will never change. There are new[] and delete[] but there's hardly ever a reason to use them.
What realloc does in C is likely to be just a malloc, memcpy and free, anyway, although memory managers are allowed to do something clever if there is enough contiguous free memory available.
Resizing in C++ is awkward because of the potential need to call constructors and destructors.
I don't think there's a fundamental reason why in C++ you couldn't have a resize[] operator to go with new[] and delete[], that did something similar to this:
newbuf = new Type[newsize];
std::copy_n(oldbuf, std::min(oldsize, newsize), newbuf);
delete[] oldbuf;
return newbuf;
Obviously oldsize would be retrieved from a secret location, same is it is in delete[], and Type would come from the type of the operand. resize[] would fail where the Type is not copyable - which is correct, since such objects simply cannot be relocated. Finally, the above code default-constructs the objects before assigning them, which you would not want as the actual behaviour.
There's a possible optimisation where newsize <= oldsize, to call destructors for the objects "past the end" of the newly-ensmallened array and do nothing else. The standard would have to define whether this optimisation is required (as when you resize() a vector), permitted but unspecified, permitted but implementation-dependent, or forbidden.
The question you should then ask yourself is, "is it actually useful to provide this, given that vector also does it, and is designed specifically to provide a resize-able container (of contiguous memory--that requirement omitted in C++98 but fixed in C++03) that's a better fit than arrays with the C++ ways of doing things?"
I think the answer is widely thought to be "no". If you want to do resizeable buffers the C way, use malloc / free / realloc, which are available in C++. If you want to do resizeable buffers the C++ way, use a vector (or deque, if you don't actually need contiguous storage). Don't try to mix the two by using new[] for raw buffers, unless you're implementing a vector-like container.
Here's a std::move example implementing a simple vector with a realloc (*2 each time we hit the limit). If there's a way to do better than the copy I have below, pls let me know.
Compile as:
g++ -std=c++2a -O2 -Wall -pedantic foo.cpp
Code:
#include <iostream>
#include <algorithm>
template<class T> class MyVector {
private:
T *data;
size_t maxlen;
size_t currlen;
public:
MyVector<T> () : data (nullptr), maxlen(0), currlen(0) { }
MyVector<T> (int maxlen) : data (new T [maxlen]), maxlen(maxlen), currlen(0) { }
MyVector<T> (const MyVector& o) {
std::cout << "copy ctor called" << std::endl;
data = new T [o.maxlen];
maxlen = o.maxlen;
currlen = o.currlen;
std::copy(o.data, o.data + o.maxlen, data);
}
MyVector<T> (const MyVector<T>&& o) {
std::cout << "move ctor called" << std::endl;
data = o.data;
maxlen = o.maxlen;
currlen = o.currlen;
}
void push_back (const T& i) {
if (currlen >= maxlen) {
maxlen *= 2;
auto newdata = new T [maxlen];
std::copy(data, data + currlen, newdata);
if (data) {
delete[] data;
}
data = newdata;
}
data[currlen++] = i;
}
friend std::ostream& operator<<(std::ostream &os, const MyVector<T>& o) {
auto s = o.data;
auto e = o.data + o.currlen;;
while (s < e) {
os << "[" << *s << "]";
s++;
}
return os;
}
};
int main() {
auto c = new MyVector<int>(1);
c->push_back(10);
c->push_back(11);
}