I get segmentation faults when I use the =-operator to copy a struct that contains a std::vector to uninitialized memory.
The critical code looks like that:
template<typename T>
ComponentContainer
{
T* buffer;
size_t capacity;
size_t m_size;
public:
ComponentContainer();
~ComponentContainer();
size_t size();
void resize(size_t size);
T & operator[](size_t index);
};
template<typename T>
void ComponentContainer<T>::resize(size_t newSize)
{
if(this->m_size >= newSize)
{
this->m_size = newSize;
}
else
{
if(this->capacity < newSize)
{
const size_t newCapacity = capacity*2;
T* newBuffer = (T*)malloc(newCapacity*sizeof(T));
for(size_t i = 0; i<m_size; i++)
{
// checks if this->buffer[i] is valid intialized memory
if(pseudo_checkIfElementIsInitialized(i))
{
// when this is uncommented no segfault happens
//new (&newBuffer[i]) T();
newBuffer[i] = this->buffer[i]; // <- segfault happens here
}
}
this->capacity = newCapacity;
free(this->buffer);
this->buffer = newBuffer;
}
this->m_size = newSize;
}
}
The T-type is a struct with a std::vector of structs when I get the segfault.
I suspect that the std::vector =-operator uses somehow the left side variable newBuffer[i] and the segmentation fault happens since newBuffer[i] is not initialized.
Objects will be created only with in-placement new with the function T & operator[](size_t index). The malloc should only allocate the memory without initializing anything.
I tried to write a simple example but that hasn't worked out so well:
#include <iostream>
#include <vector>
struct Hello
{
Hello()
{
std::cout << "constructor" << std::endl;
}
~Hello()
{
std::cout << "destructor" << std::endl;
}
std::vector<double> v = std::vector<double>(1);
};
int main()
{
Hello* buffer = (Hello*)malloc(1*sizeof(Hello));
char* noise = (char*)buffer;
for(size_t i = 0; i<sizeof(Hello); i++)
{
noise[i] = 100;
}
auto tmp = Hello();
tmp.v[0] = 6.6;
//new (&buffer[0]) Hello();
buffer[0] = tmp;
std::cout << buffer[0].v[0] << std::endl;
return 0;
}
It works fine without segfault. I assume that is because the uninitialized memory was just by chance ok for the std::vector =-operation.
So
a) is that theory correct
and if yes
b) how to solve this problem without using a default constructor (T()) for every class that i use as T for my ComponentContainer
Well, yeah. You can't assign to an object that doesn't exist.
Uncomment the line that fixes it!
If you can't default construct, then copy construct:
new (&newBuffer[i]) T(this->buffer[i]);
And if you can't do that, then, well, you know the rest.
The malloc should only allocate the memory without initializing anything.
Is it possible that you've underestimated the weight of this statement? You don't just get memory then decide whether or not to initialise it with some values. You have to actually create objects before using them; this is not optional. You're programming C++, not manipulating bits and bytes on a tape :)
Related
I created a queue data structure using a struct and a dynamically allocated array, I don't understand what is the right way to free or delete it without any memory leaks.
I have tried using the following:
delete[] q->data;
delete[] &(q->data);
delete &(q->data);
#include "queue.h"
void initQueue(queue* q, unsigned int size)
{
q->maxSize = size;
q->size = 0;
q->data = new unsigned int[size];
q->front = 0;
q->rear = 0;
}
void enqueue(queue* q, unsigned int newValue)
{
if (q->size != q->maxSize)
{
q->data[q->rear] = newValue;
q->size++;
q->rear++;
}
else
{
std::cout << "Queue is full! you can clean it and initialize a new one" << std::endl;
}
}
int dequeue(queue* q)
{
int i = 0;
if (q->size == 0)
{
std::cout << "Queue is empty!" << std::endl;
return EMPTY;
}
else
{
q->front++;
q->size--;
return q->data[q->front];
}
}
void cleanQueue(queue* q)
{
//the delete function
}
The technical right answer here is to delete q->data, as others have suggested. But...
right way to free or delete it without any memory leaks
The right way in C++, unless you're doing some exotic with allocation, is not to do your own memory management. Write a class that allocates in the constructor, and deletes in the destructor, as Chris suggested, is a great way to learn about RAII and how it saves you from the mental burden of manually writing "delete" everywhere.
But the right right way, if someone was paying me? I'd skip all that and use a vector.
#include <vector>
class MyQueue {
public:
MyQueue(unsigned int size) : data(size) { }
void enqueue(unsigned int value) { /* whatever... */ }
int dequeue() { /* whatever... */ }
private:
std::vector<unsigned int> data;
};
When this class goes out of scope or gets deleted, the vector will automatically be cleaned up. You don't even need to free or delete anything.
Im trying to write a class that stores an id and a value in an container class.
Im using an nested class as my data structure.
When im compiling the code sometimes it prints perfectly, sometimes it prints nothing and sometimes it prints half of the data then stops.
When i debug the code the same weird behavior occours, when it fails during debug it throws an error "Map.exe has triggered a breakpoint.", the Error occours in the print method when im using cout.
cmap.h
#pragma once
class CMap
{
public:
CMap();
~CMap();
CMap& Add(int id, int value);
void print() const;
private:
class container
{
public:
~container();
int container_id = 0;
int container_value = 0;
};
container* p_komp_;
int dim_ = -1;
void resize();
};
cmap.cpp
#include "cmap.h"
#include <iostream>
using namespace std;
CMap::CMap()
{
p_komp_ = new container[0];
}
CMap::~CMap()
{
p_komp_ = nullptr;
cout << "destroy cmap";
}
CMap& CMap::Add(int id, int value)
{
resize();
p_komp_[dim_].container_id = id;
p_komp_[dim_].container_value = value;
return *this;
}
void CMap::resize()
{
container* temp_array = new container[++dim_];
if (dim_ == 0)
{
temp_array[0].container_id = p_komp_[0].container_id;
temp_array[0].container_value = p_komp_[0].container_value;
}
for (unsigned i = 0; i < dim_; i++)
{
temp_array[i].container_id = p_komp_[i].container_id;
temp_array[i].container_value = p_komp_[i].container_value;
}
p_komp_ = temp_array;
}
void CMap::print() const
{
for (unsigned i = 0; i <= dim_; i++)
{
cout << p_komp_[i].container_id;
cout << p_komp_[i].container_value;
}
}
CMap::container::~container()
{
cout << "destruct container";
}
Map.cpp
#include "cmap.h"
#include <iostream>
using namespace std;
void main(void)
{
CMap m2;
m2.Add(1, 7);
m2.Add(3, 5);
m2.print();
}
These two things are a possible reason for your problem:
int dim_ = -1;
and
container* temp_array = new container[++dim_];
When you allocate, you increase dim_ from -1 to 0. That is you create a zero-sized "array", where every indexing into it will be out of bounds and lead to undefined behavior.
You also have memory leaks since you never delete[] what you new[]. I didn't look for more problems, but there probably a more.
And an "array" (created at compile-time or through new[]) will have indexes from 0 to size - 1 (inclusive). You seem to think that the "size" you provide is the top index. It's not, it's the number of elements.
It seems to me that you might need to take a few steps back, get a couple of good books to read, and almost start over.
I'm attempting to write a simple pool allocator for allocation and deallocation in c++ as part of a uni course task. We were given a reference to to git-user floooh's oryol engine, https://github.com/floooh/oryol/blob/master/code/Modules/Core/Memory/poolAllocator.h, hence I try to do something similar by splitting the pool into puddles that are allocated when needed. Starting with one and then incrementing as memory demands increase.
Each puddle in my case maintains its own free list of nodes and I fail already in creating the first puddle: I get segmentation fault when I try to access node struct data members. Below is my pool allocator class description along with constructor and function for adding a puddle. I commented in caps lock "SEGMENTATION FAULT" in allocNewPuddle() where it fails, line 10 in that function.
Class description:
template<class T> class memAllocator {
public:
memAllocator();
~memAllocator();
struct Puddle;
struct mNode {
mNode* nextN;
mNode* prevN;
uint puddle;
};
struct Puddle {
mNode* headN_free;
mNode* headN_occ;
};
uint numPuddles;
static const uint nodesInPuddle = 512;
static const uint maxPuddles = 512;
Puddle* puddles[maxPuddles];
uint nodeSize;
uint elemSize;
uint puddleStructSize;
void allocNewPuddle();
void* allocate();
void deallocate(void* obj);
void* findNextFreeNode();
template<typename... ARGS> T* create(ARGS&&... args);
void destroy(T* obj);
};
Constructor:
template<class T>
memAllocator<T>::memAllocator() // creates instance of allocator starting with one puddle allocated
{
this->numPuddles = 0;
this->nodeSize = sizeof(mNode);
this->elemSize = nodeSize + sizeof(T);
this->puddleStructSize = sizeof(Puddle);
allocNewPuddle();
}
Add a new puddle:
template<class T>
void memAllocator<T>::allocNewPuddle() // allocates a new puddle
{
// allocate memory for one puddle
assert(numPuddles < maxPuddles);
Puddle* newPuddle = (Puddle*) malloc(puddleStructSize + nodesInPuddle * elemSize);
// allocate nodes in free list pointed to by puddle struct
newPuddle->headN_free = (mNode*) (newPuddle + puddleStructSize + (nodesInPuddle-1)*elemSize);
for (int i = nodesInPuddle-2; i >= 0; i--) {
mNode* curNode = (mNode*) (newPuddle + puddleStructSize + i*elemSize);
// Fails here when attempting to access mNode struct members
curNode->puddle = numPuddles; // SEGMENTATION FAULT HERE ON FIRST ITERATION
curNode->prevN = nullptr;
curNode->nextN = newPuddle->headN_free;
curNode->nextN->prevN = curNode;
newPuddle->headN_free = curNode;
}
newPuddle->headN_occ = nullptr;
puddles[numPuddles] = newPuddle;
numPuddles++;
}
Here is my main.cc:
#include "memAllocator.h"
#include <iostream>
class Test {
public:
Test();
~Test();
int arr[5];
};
Test::Test() {
for (int i = 0; i < 5; i++) {
this->arr[i] = i;
}
}
Test::~Test() {
std::cout << "destructor called" << std::endl;
}
int main(int argc, char* argv[]) {
memAllocator<Test> memPool = memAllocator<Test> ();
Test* test = memPool.create();
for (int i = 0; i < 5; i++) {
std::cout << test->arr[i] << std::endl;
}
memPool.destroy(test);
for (int i = 0; i < 5; i++) {
std::cout << test->arr[i] << std::endl;
}
}
My guess is that I am doing something horribly naïve with c++ pointers, but from what I know the above should work. If not then I look forward to a good scolding.
Oh, and as you can see I'm not bothering to align memory since it is a small assignment, and as I understand this is not essential for it to work it only makes it faster, but is it possible this can cause wrong memory to be read and written to as more is demanded?
You have incorrect address calculation in line
mNode* curNode = (mNode*) (newPuddle + puddleStructSize + i*elemSize);
newPuddle is Puddle pointer, but you trying to add bytes. Thus you have new address far beyond end of allocated memory buffer. So you must add explicit cast to byte pointer (char, uint8_t etc)
mNode* curNode = (mNode*) ((char*)newPuddle + puddleStructSize + i*elemSize);
You must fix this line too
newPuddle->headN_free = (mNode*) (newPuddle + puddleStructSize + (nodesInPuddle-1)*elemSize);
I have a recursive function that requires me to create a new array every time the function is called. The function also requires the array that was previously created:
void myFunc(int* prevArray)
{
int newSize;
//do some calculations to find newSize
int* newArray;
newArray = new int[newSize];
//do some calculations to fill newArray
//check some stopping condition
myFunc(newArray);
}
This function leaks memory, but I can't avoid that by adding
delete[] newArray;
since I can only add that after calling the function again. How can I solve this?
You can solve this by making use of dynamic memory allocation.
// allocate initial size
const int INITIAL_SIZE = 5;
int *myArray = malloc(sizeof(int) * INITIAL_SIZE));
int myFunc(int *aArray, int numAllocated) {
int numElements = calculateNewSize();
if (numElements != numAllocated) {
// allocate new size
realloc(aArray, (numElements * sizeof(int));
}
return numElements;
}
Now you can call myFunc like this:
int numElements;
numElements = myFunc(myArray, numElements);
When your done using myFunc don't forget to free the memory
free(myArray);
Try something like
void myFunc(int* prevArray)
{
int newSize;
...newArray = new int[newSize];
myFunc(newArray);
delete[] newArray;
}
or better yet use std::unique_ptr to control the newArray memory. In this way you will follow the rule of thumb regarding dynamic memory - that it should have one owner, responsible for both allocating and freeing it.
You might just use a vector and swap the new result into the final result.
#include <iostream>
#include <vector>
struct X { ~X() { std::cout << "Destruction\n"; } };
void recursive(unsigned n, std::vector<X>& result) {
// Put new_result in a scope for destruction
{
std::vector<X> new_result(1);
// Do something
// The previous result is no longer needed
std::swap(result, new_result);
}
// Next recursion
if(n) {
std::cout << "Call\n";
recursive(--n, result);
}
}
int main() {
std::vector<X> result(1);
std::cout << "Call\n";
recursive(3, result);
return 0;
}
I'm working on an email validation program for my cmpsci class and am having trouble with this one part.
What I'm doing is reading a list of valid top level domains from a text file into a vector class I wrote myself (I have to use a custom vector class unfortunately). The problem is that the program reads in and adds the first few domains to the vector all well and fine, but then crashes when it gets to the "org" line. I'm completely stumped why it works for the first few and then crashes.
Also, I have to use a custom string class; that's why I have the weird getline function (so I get the input in a char* for my String constructor). I've tried using the standard string class with this function and it still crashed in the same way so I can rule out the source of the problem being my string class. The whole program is quite large so I am only posting the most relevant parts. Let me know if more code is needed please. Any help would be awesome since I have no clue where to go from here. Thanks!
The ReadTlds function:
void Tld::ReadTlds() {
// Load the TLD's into the vector
validTlds = Vector<String>(0); // Init vector; declaration from header file: "static Vector<String>validTlds;"
ifstream in(TLD_FILE);
while(!in.eof()) {
char tmpInput[MAX_TLD_LENGTH]; // MAX_TLD_LENGTH equals 30
in.getline(tmpInput, MAX_TLD_LENGTH);
validTlds.Add(String(tmpInput)); // Crashes here!
}
}
My custom vector class:
#pragma once
#include <sstream>
#define INIT_CAPACITY 100
#define CAPACITY_BOOST 100
template<typename T> class Vector {
public:
// Default constructor
Vector() {
Data=NULL;
size=0;
capacity=INIT_CAPACITY;
}
// Init constructor
Vector(int Capacity) : size(0), capacity(Capacity) {
Data = new T[capacity];
}
// Destructor
~Vector() {
size=0;
Data = NULL;
delete[] Data;
}
// Accessors
int GetSize() const {return size;}
T* GetData() {return Data;}
void SetSize(const int size) {this->size = size;}
// Functions
void Add(const T& newElement) {
Insert(newElement, size);
}
void Insert(const T& newElement, int index) {
// Check if index is in bounds
if((index<0) || (index>capacity)) {
std::stringstream err;
err << "Vector::Insert(): Index " << index << " out of bounds (0-" << capacity-1 << ")";
throw err.str();
}
// Check capacity
if(size>=capacity)
Grow();
// Move all elements right of index to the right
for(int i=size-1; i>=index; i--)
Data[i+1]=Data[i];
// Put the new element at the specified index
Data[index] = newElement;
size++;
}
void Remove(int index) {
// Check if index is in bounds
if((index<0) || (index>capacity-1)) {
std::stringstream err;
err << "Vector::Remove():Index " << index << " out of bounds (0-" << capacity-1 << ")";
throw err.str();
}
// Move all elements right of index to the left
for(int i=index+1; i<size; i++)
Data[i-1]=Data[i];
}
// Index operator
T& operator [] (int index) const {
// Check if index is in bounds
if((index<0) || (index>capacity-1)) {
std::stringstream err;
err << "Vector operator[]:Index " << index << " out of bounds (0-" << capacity-1 << ")";
throw err.str();
}
return Data[index];
}
// Assignment oper
Vector<T>& operator = (const Vector<T>& right) {
Data = new T[right.GetSize()];
for(int i=0; i<right.GetSize(); i++)
Data[i] = right[i];
size = right.GetSize();
return *this;
}
private:
T *Data;
int size; // Current vector size
int capacity; // Max size of vector
void Grow() {
capacity+=CAPACITY_BOOST;
T* newData = new T[capacity];
for(int i=0; i<capacity; i++)
newData[i] = Data[i];
// Dispose old array
Data = NULL;
delete[] Data;
// Assign new array to the old array's variable
Data = newData;
}
};
The input file:
aero
asia
biz
cat
com
coop
edu
gov
info
int
jobs
mil
mobi
museum
name
net
org <-- crashes when this line is read
pro
tel
travel
The error Visual Studio throws is:
Unhandled exception at 0x5fb04013 (msvcp100d.dll) in Email4.exe: 0xC0000005: Access violation reading location 0xabababbb.
The problem is in your grow function:
void Grow() {
capacity+=CAPACITY_BOOST;
T* newData = new T[capacity];
for(int i=0; i<capacity; i++)
newData[i] = Data[i];
You increase the capacity, but then copy elements that didn't exist in the old array. It should be something like:
void Grow() {
int old_capacity = capacity;
capacity+=CAPACITY_BOOST;
T* newData = new T[capacity];
for(int i=0; i<old_capacity; i++)
newData[i] = Data[i];
You also NULL out Data before deleting it in both Grow and the destructor, which causes a memory leak. In both cases, you really don't need to set it to NULL at all, since there's no change of it being accidentally double-deleted (in Grow it's set to a new pointer immediately, in the destructor the object's lifetime is over). So just
delete[] Data;
alone is fine.
Also I think
if(size>=capacity)
can be:
if(size == capacity)
since size should never be over capacity. That would mean you'd already overflowed the buffer.
Matthew is probably right. Still, there's a valuable lesson to be learned here.
When you hit a problem like this, don't stop walking your code in your ReadTlds function. Keep walking inside the Vector class. Functions like Insert and Grow probably hold the error, but if you don't walk through them, you'll never find it.
Debugging is it's own very special skill. It takes a long time to get it down pat.
edit it's a late night and I misread your code, but I left my post to comment back
Also in the default ctor you do
Data = NULL;
capacity=INIT_CAPACITY;
(EDIT: expanded explanation here)
But never allocate the memory for Data. Shouldn't it be:
Vector() {
Data= new T[INIT_CAPCITY];
size=0;
capacity=INIT_CAPACITY;
}
And remove is missing
--size
EDIT:
Fellow readers help me out here:
Data is of type T* but everywhere else you are assigning and allocating it just like T instead of T* . My C++ days are too long gone to remember whether using a T& actually resolves this.
Also I can't remember that if you have an array of pointers and destruct it, that the dtor for the single instances in the array are destroyed.
Also in the assignment operator, wouldn't you be copying the pinters? so you just have to rely on the fact the the instance where you copyid from is never deleted (because then your objects would be dead too).
hth Mario