Self-made ugly vector - c++

I've got some training example of selt-made vector, it's not template for simplicity:
class UglyStringsVector {
public:
UglyStringsVector() = default;
explicit UglyStringsVector(size_t size);
UglyStringsVector(const UglyStringsVector&);
~UglyStringsVector();
std::string &operator[](size_t index);
std::string *begin();
std::string *end();
const std::string *begin() const;
const std::string *end() const;
size_t Size() const;
size_t Capacity() const;
void PushBack(std::string value);
void operator=(const UglyStringsVector &other);
private:
std::string *data = nullptr;
size_t size = 0;
size_t capacity = 0;
void ExpandIfNeeded();
};
Assignment operator is not implemented correctly:
UglyStringsVector& UglyStringsVector::operator=(const UglyStringsVector &other) {
delete[] data;
data = new std::string[other.capacity];
size = other.size;
capacity = other.capacity;
copy(other.begin(), other.end(), begin());
return *this;
}
As we see here, when this == &other (I don't check this condition on purpose of question), it deletes its own memory (of course this is wrong), and then reallocates new strings on the same place (data = new std::string[other.capacity];), strings are not uninitialized, because default constructor was called during operator new[], and then copy strings to themselves (copy(other.begin(), other.end(), begin());).
Lets imagine than losing memory is not problem :-)
Something whispers to me that copying memory to itself is undefined behavior, but I'm not sure.
The question: is there any undefined behavior?

Assuming that data is a valid pointer or nullptr, then actually there's no UB at all.
With new std::string[other.capacity] you create an "array" of default-initialized std::string objects. A default-initialized (default-constructed basically) std::string is a valid but empty string.
You then copy this array of empty strings to itself, which is fine.
Regarding the self-copying, it's similar to
int a = 0;
a = a;
which is weird but fine.

There is no any undefined behavior. You simply delete a memory part which is pointed by the data pointer, and then you re-allocate a new array and assign it to data.

Related

Placement New on already existing object in SharedMemory

I have two programs. The first allocates a Shared-Memory file and the second reads from it.. I am using placement-new to place objects into this memory guaranteeing that the objects do NOT use new or allocate any memory outside of the Shared-Memory file.
My Array structure:
template<typename T, size_t Size>
struct SHMArray {
SHMArray() : ptr(elements) {}
SHMArray(const SHMArray& other) { std::copy(other.begin(), other.end(), begin()); }
SHMArray(SHMArray&& other)
{
std::swap(other.ptr, ptr);
std::fill_n(ptr.get(), Size, T());
}
~SHMArray()
{
std::fill_n(ptr.get(), Size, T());
}
constexpr bool empty() const noexcept
{
return Size == 0;
}
constexpr size_type size() const noexcept
{
return Size;
}
T& operator[](std::size_t pos)
{
return *(ptr.get() + pos);
}
constexpr const T& operator[](std::size_t pos) const
{
return *(ptr.get() + pos);
}
T* data() noexcept
{
return ptr.get();
}
constexpr const T* data() const noexcept
{
return ptr.get();
}
private:
offset_ptr<T> ptr;
T elements[];
};
Program 1:
int main()
{
//Allocate a shared memory file of 1mb..
auto memory_map = SharedMemoryFile("./memory.map", 1024 * 1024, std::ios::in | std::ios::out);
memory_map.lock();
//Pointer to the shared memory.
void* data = memory_map.data();
//Place the object in the memory..
SHMArray<int, 3>* array = ::new(data) SHMArray<int, 3>();
(*array)[0] = 500;
(*array)[1] = 300;
(*array)[2] = 200;
memory_map.unlock(); //signals other program it's okay to read..
}
Program 2:
int main()
{
//Open the file..
auto memory_map = SharedMemoryFile("./memory.map", 1024 * 1024, std::ios::in | std::ios::out);
memory_map.lock();
//Pointer to the shared memory.
void* data = memory_map.data();
//Place the object in the memory..
//I already understand that I could just cast the `data` to an SHMArray..
SHMArray<int, 3>* array = ::new(data) SHMArray<int, 3>();
for (int i = 0; i < array.size(); ++i)
{
std::cout<<(*array)[i]<<"\n";
}
memory_map.unlock(); //signals other program it's okay to read..
}
Program One placed the SHMArray in memory with placement new. Program Two does the same thing on top of program one's already placed object (overwriting it). Is this undefined behaviour? I don't think it is but I want to confirm.
Neither program calls the destructor array->~SHMVEC(); I also don't think this leaks as long as I close the MemoryMapped file then it should all be fine.. but I want to make sure this is fine. If I ran the programs again on the same file, it shouldn't be a problem.
I am essentially making the assumption that placement new is working as if I placed a C struct in memory in this particular scenario via: struct SHMArray* array = (struct SHMArray*)data;.. Is this correct?
I am essentially making the assumption that placement new is working
as if I placed a C struct in memory in this particular scenario via:
struct SHMArray* array = (struct SHMArray*)data;.. Is this correct?
No, this is not correct. Placement new also invokes the object's appropriate constructor. "struct SHMArray* array = (struct SHMArray*)data;" does not invoke any object's constructor. It's just a pointer conversion cast. Which does not invoke anyone's constructor. Key difference.
In your sample code, you do actually want to invoke the templated object's constructor. Although the shown example has other issues, as already mentioned in the comments, this does appear to be what needs to be done in this particular situation.
But insofar as the equivalent of placement new versus a pointer cast, no they're not the same. One invokes a constructor, one does not. new always invokes the constructor, whether it's placement new, or not. This is a very important detail, that's not to be overlooked.

Is it really safe not to check in the copy assignemt operator whether an object is assigned to itself?

Here is an example implementing "Rule of Three" which I found:
class Array {
public:
int size;
int* vals;
Array() : size(0), vals(NULL){}
Array( int s, int* v );
Array(const Array&); // 1
Array& operator=(const Array&); // 2
~Array(); // 3
};
Array::~Array() {
delete []vals;
vals = NULL;
}
Array::Array( int s, int* v ){
size = s;
vals = new int[size];
std::copy( v, v + size, vals );
}
Array::Array(const Array& rhs):
size(rhs.size),
vals((rhs.size) ? new int[size] : NULL)
{
if(size)
std::copy(rhs.vals, rhs.vals + rhs.size, vals);
}
Array& Array::operator=(const Array& rhs){
// if(this == &rhs) // no need
// return *this;
int* a = (rhs.size)? new int[rhs.size] : NULL; // this is why we don't need the above check: if this line throws then vals is untouched. if this is ok (local variable) then continue (next won't throw).
std::copy(rhs.vals, rhs.vals + rhs.size, a); // copying to a even (self assignment won't harm)
delete[] vals;
vals = a;
size = rhs.size;
return *this;
}
As you can see above the check in the Copy Assignment Operator is removed as the fact being creating a local variable then delete the member pointer and assign it the local one. But what matters me if I write:
int main() {
int vals[ 4 ] = { 11, 22, 33, 44 };
Array a1( 4, vals );
a1 = a1; // here I assigned a1 to itself
return 0;
}
I assigned a1 to itself does this mean a1's valsis removed and then assigned the local one a in the Copy assignment operator? Is this a correct way? Does my code has some pitfalls?
Any tip, advice is highly appreciated.
The copy assignment operator will function, in the sense that self-assignment will have the expected behavior: the value content of the array will be unchanged.
What you're losing by not doing the test is that, if you already hold an array, you will allocate an array you don't need, perform a copy you don't have to do, then destroy something you could have kept.
Whether this matters for performance... that will depend heavily on usage-dependent factors. After all, this is only a problem if you perform a self-copy. How often do you do that? And if you really don't do it that often (or ever), then the test is just a conditional branch you don't need.
At the same time, consider the definition of vector. It has very specific circumstances for when iterators/pointers/references into the vector become invalidated. And copying the vector is not one of them. So if the location of object storage is a part of the interface of your array type (the way it is for vector), then doing self-copies has broader implications for your interface.

segmentation fault with deep copy

I am trying to make a deep copy (for copy on write) of an object but I get a segmentation fault.
I am using a hashtable with linked list.
class Person
{
public:
Person(const char * id,int nb)
{
this->id=strdup(id);
this->nb=nb;
this->init=init;
this->next=NULL;
}
Person(const Person& rhs) :
nb(rhs.nb),
init(rhs.init),
id(strdup(rhs.id)),
next(rhs.next == NULL ? NULL : new Person(*rhs.next)) {}
char* strdup(char const* in)
{
char* ret = new char[strlen(in)+1];
strcpy(ret, in);
return ret;
}
int nb,init;
const char * id;
Person *next;
};
Hashtable deepcopy (const Hashtable& rhs)
{
num[0]=num[0]-1;
Person** array=rhs.table;
Hashtable autre;
for (int i = 0 ; i < size; ++i)
if (autre.table[i]!=NULL)
autre.table[i] = new Person(*array[i]);
return autre;
num[0]=1;
}
the attributs of my class Hashtable:
Person **table;
int* num;
EDIT: this problem seem to be fixed.
What is wrong with my deep copy? I don't understand. I think that my copy constructor is good but I don't understand why I get a seg fault when I run it.
This code must be fixed:
for (int i = 0 ; i < size; ++i)
autre.table[i] = new Person(*array[i]);
table has fixed size, and it's filled with null-pointers. In your loop, you don't check if the element to be copied is a null-pointer, so you derefence it and try to copy the entity which even doesn't exist.
for (int i = 0 ; i < size; ++i) {
if(array[i] != NULL) {
autre.table[i] = new Person(*array[i]);
}
}
PS: It's better to use nullptr instead of NULL.
Problems that I see:
Default constructor of Person.
Person(const char * id,int nb)
{
this->id=id;
this->next=NULL;
}
If I use
Person foo()
{
char id[] = "John";
return Person(id, 0);
}
Person a = foo();
Then the stack memory used for holding "John" in foo is now held on to by a, which will lead to undefined behavior.
You need to take ownership of the input string. Use std::string for id instead of char const*.
Copy constructor of Person.
The statement
id(rhs.id),
will be a problem if you decide to use char const* as type for id. If you switch it to std::string, it won't be a problem.
Copy constructor of HashTable makes a shallow copy of table. This will be a problem if you decide to delete the table in the destructor of HashTable. If you don't delete table in the destructor of HashTable, you have a memory leak.
In deepcopy, you are not checking whether array[i] is NULL before dereferencing it. This has already been pointed out by #alphashooter. Additionally, you are creating a deep copy in a local variable of the function,autre. The deep copy is not visible outside the function unless you return autre from it.
EDIT
Since you are not allowed, to use std::string, you will have to allocate memory for the char const* in the default constructor as well as the copy constructor. If your platform has the non-standard function strdup and you are allowed to use it, you can change the default constructor to:
Person(const char * id,int nb)
{
this->id=strdup(id);
this->next=NULL;
}
You need to make a similar change to the copy constructor.
If you don't have strdup or you are not allowed to use it, you can define it. It's a very simple function to write.
char* strdup(char const* in)
{
char* ret = new char[strlen(in)+1];
strcpy(ret, in);
return ret;
}

How can I do equivalent of memcpy from a raw array to a std::vector?

I have a class that has (amongst many other things) a pointer to unsigned char that gets deleted and reallocated to store some data from another array. This done with a function
class MyClass {
private:
unsigned char* m_Buffer;
int m_BufferSize;
public:
bool SetBuffer(int iSize, const unsigned char* pArray);
};
bool MyClass::SetBuffer(int iSize, const unsigned char* pArray) {
bool bOK = false;
if (pArray != NULL && iSize > 0) {
delete [] m_Buffer;
m_Buffer = new unsigned char[iSize];
memcpy(m_Buffer,pArray,iSize);
m_BufferSize = iSize;
bOK = true;
}
return bOK;
}
I dont like this code at all, and I would really like to replace the pointer with a std::vector<unsigned char>. My question is, how would I perform the memcpy aspect? If I were passing a vector in as argument to my function, I could copy it using iterators, but I have no control over parameter argument type so I am stuck with unsigned char* . Is there a way of using iterators, or sizing the vector to the right size and then accessing its internal array so that I can still copy the data with memcpy ? Or even better something using iterators?? I know I could use a loop and push_back but that seems painfully inefficient to me. Any suggestions will be gratefully received.
Actually, iterators are modelled from pointers and therefore pointers within an array are considered to implement the RandomAccessIterator concept.
Therefore:
m_buffer.assign(pArray, pArray + Size);
I really advise you to avoid raw pointers this way. I think that is a better idea to manage std::vectors instead of the raw pointers.
class MyClass {
private:
std::vector<unsigned char> m_Buffer;
// No size member is needed, it is stored in m_Buffer
public:
// No size parameter is needed, it is stored in Array
void SetBuffer(const std::vector<unsigned char> &Array);
};
void MyClass::SetBuffer(const std::vector<unsigned char> &Array) {
std::copy(Array.begin(), Array.end(), m_Buffer.begin());
}
Assuming that your dessing forces to have a raw managed for MyClass you will take care of this pointer on copy constructors and operator = (or get rid of it instead):
MyClass::MyClass(const MyClass &Class) {
m_BufferSize = Class.m_BufferSize;
m_Buffer = new new unsigned char[m_BufferSize];
memcpy(m_Buffer, Class.m_Buffer, m_BufferSize);
}
MyClass::operator =(const MyClass &Class) {
if (m_Buffer) delete [] m_Buffer;
m_BufferSize = Class.m_BufferSize;
m_Buffer = new new unsigned char[m_BufferSize];
memcpy(m_Buffer, Class.m_Buffer, m_BufferSize);
}
If you don't take care of the MyClass managed pointers in the copy constructor and operator = you will end with two instances of MyClass managing the same memory.

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

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. :)