This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I have made a small mechanism that replaces the regular new operator.
Basically we allocate a pool of memory (like 16mb) and when new is called, return
an offset to it that grows until there is no more room and we make another pool. A pool
is deleted only when all of the elements in that pool are freed.
I have tested this class and it works great and around 8-15 times faster than the original new.
There is a problem however: I incorporated it into my other project which is huge in size, it
works normally except the memory usage grows very quickly. Basically the pools aren't freed because
some items in them are not deleted at all. Also, there are many calls to new(0) from STL containers
to which I dont know how should it respond.
Here is the code:
namespace rt
{
class pool
{
friend class alloc;
private:
unsigned int _numRecords;
unsigned int _sizeLeft;
char* _ptr;
char* _data;
};
class alloc
{
public:
alloc();
alloc(int mb);
~alloc();
void* allocate(unsigned int size);
void constructPool(unsigned int idx);
void destroyPool(unsigned int idx);
void deallocate(void* ptr);
private:
const static unsigned int _numPools = 256;
const static unsigned int _poolSize = 15*1024*1024;
const static unsigned int _poolReplaceBound = 1*1024*1024; // if 1mb or less left we can replace it
pool* _pools[_numPools];
unsigned int _curPoolIdx;
};
That was the header.
Here is the implementation:
namespace rt
{
class pool
{
friend class alloc;
private:
unsigned int _numRecords;
unsigned int _sizeLeft;
char* _ptr;
char* _data;
};
class alloc
{
public:
alloc();
alloc(int mb);
~alloc();
void* allocate(unsigned int size);
void constructPool(unsigned int idx);
void destroyPool(unsigned int idx);
void deallocate(void* ptr);
private:
const static unsigned int _numPools = 256;
const static unsigned int _poolSize = 15*1024*1024;
const static unsigned int _poolReplaceBound = 1*1024*1024; // if 1mb or less left we can replace it
pool* _pools[_numPools];
unsigned int _curPoolIdx;
};
extern alloc default_allocator;
}
#define RT_SAFE_MEM
namespace rt
{
alloc default_allocator;
alloc::alloc()
{
for(int i = 0; i < _numPools; i++) _pools[i] = NULL;
_curPoolIdx = 0;
constructPool(_curPoolIdx);
}
alloc::~alloc()
{
}
void alloc::constructPool(unsigned int idx)
{
_pools[idx] = (pool*)malloc(sizeof(pool));
_pools[idx]->_numRecords = 0;
_pools[idx]->_sizeLeft = _poolSize;
_pools[idx]->_data = (char*)calloc(_poolSize, 1);
_pools[idx]->_ptr = _pools[idx]->_data;
}
void alloc::destroyPool(unsigned int idx)
{
free(_pools[idx]->_data);
free(_pools[idx]);
_pools[idx] = NULL;
}
void* alloc::allocate(unsigned int size)
{
if(size == 0)
{
return NULL;
}
#ifdef RT_SAFE_MEM
if(size > _poolSize)
{
MessageBox(NULL, "Allocation size exceeded maximum.", "Executor", MB_OK);
return NULL;
}
if(*(_pools[_curPoolIdx]->_ptr) != 0)
{
//leak
unsigned int leaksize = strlen(_pools[_curPoolIdx]->_ptr);
char str[50];
sprintf(str, "Memory corruption detected: wrote extra %u bytes. \nExporting to corrupt.txt", leaksize);
FILE* fp = fopen("corrupt.txt", "w");
fwrite(_pools[_curPoolIdx]->_ptr, 1, leaksize, fp);
fclose(fp);
MessageBox(NULL, str, "Executor", MB_OK);
return NULL;
}
#endif
if(_pools[_curPoolIdx]->_sizeLeft <= size)
{
//not enough size in this pool
//make a new one
_curPoolIdx++;
//printf("expand");
constructPool(_curPoolIdx);
return allocate(size);
}
else
{
void* ans = (void*)_pools[_curPoolIdx]->_ptr;
_pools[_curPoolIdx]->_ptr+=size;
_pools[_curPoolIdx]->_sizeLeft-=size;
_pools[_curPoolIdx]->_numRecords++;
return ans;
}
}
void alloc::deallocate(void* ptr)
{
for(int i = 0; i <= _curPoolIdx; i++)
{
if(ptr >= _pools[i]->_data && ptr < _pools[i]->_ptr)
{
//pool i contains this object
//printf("found %d\n", i);
_pools[i]->_numRecords--;
if(_pools[i]->_numRecords == 0 && _pools[i]->_sizeLeft <= _poolReplaceBound)
{
//replace this pool
printf("replacing %d\n", i);
destroyPool(i);
if(_curPoolIdx == 0) constructPool(0);
else
{
for(int j = i; j < _numPools-1; j++)
{
_pools[j] = _pools[j+1];
}
_curPoolIdx--;
}
}
return;
}
}
#ifdef RT_SAFE_MEM
char str[50];
sprintf(str, "Attempted to deallocate foreign memory at 0x%.8X.", ptr);
MessageBox(NULL, str, "Executor", MB_OK);
#endif
}
}
If anyone sees a bug or a major problem, let me know.
Thanks!
I suggest you do all the below steps:
Write a test program to test that your program runs bug-free or "has any problems"
use a debugger to find bugs, not the SO's audience :-P
Instead of posting a full listing of your code you should write-up what your code does - this will serve you as a great reference point in future and also will be a useful documentation for what (and how) your code does
Related
I have a problem declaring a public/extern struct object between different .cpp files. I am trying to use the imgui logger to log some messages from a hook.
The program is going to crash on ExampleAppLog my_log2; -> ImGuiTextBuffer Buf; -> class ImVector -> if (Data)
Because i do this ExampleAppLog* my_log2 = new ExampleAppLog(); inside a .cpp that have a include .h with the struct ExampleAppLog in it, and a declaration of my_log2 .
Relevant code to crash ->
.h
struct ExampleAppLog
{
ImGuiTextBuffer Buf;
}
extern ExampleAppLog* my_log2;
.cpp
#include ".h"
ExampleAppLog* my_log2 = new ExampleAppLog(); //this line make it crash
imgui.h
struct ImGuiTextBuffer
{
ImVector<char> Buf;
}
class ImVector
{
public:
int Size;
int Capacity;
T* Data;
typedef T value_type;
typedef value_type* iterator;
typedef const value_type* const_iterator;
ImVector() { Size = Capacity = 0; Data = NULL; }
~ImVector() { if (Data) ImGui::MemFree(Data); }
inline bool empty() const { return Size == 0; }
inline int size() const { return Size; }
inline int capacity() const { return Capacity; }
inline value_type& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; }
inline const value_type& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; }
inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
inline iterator begin() { return Data; }
inline const_iterator begin() const { return Data; }
inline iterator end() { return Data + Size; }
inline const_iterator end() const { return Data + Size; }
inline value_type& front() { IM_ASSERT(Size > 0); return Data[0]; }
inline const value_type& front() const { IM_ASSERT(Size > 0); return Data[0]; }
inline value_type& back() { IM_ASSERT(Size > 0); return Data[Size-1]; }
inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size-1]; }
inline void swap(ImVector<T>& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }
inline int _grow_capacity(int size) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > size ? new_capacity : size; }
inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
inline void resize(int new_size, const T& v){ if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) Data[n] = v; Size = new_size; }
inline void reserve(int new_capacity)
{
if (new_capacity <= Capacity) return;
T* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T));
if (Data) //here is the crash. Data is 0x000000000 when crashing
memcpy(new_data, Data, (size_t)Size * sizeof(T));
ImGui::MemFree(Data);
};
Exsample code ->
.h
struct ExampleAppLog
{
ImGuiTextBuffer Buf;
ImGuiTextFilter Filter;
ImVector<int> LineOffsets; // Index to lines offset
bool ScrollToBottom;
void Clear() { Buf.clear(); LineOffsets.clear(); }
void AddLog(const char* fmt, ...) IM_FMTARGS(2)
{
int old_size = Buf.size();
va_list args;
va_start(args, fmt);
Buf.appendv(fmt, args);
va_end(args);
for (int new_size = Buf.size(); old_size < new_size; old_size++)
if (Buf[old_size] == '\n')
LineOffsets.push_back(old_size);
ScrollToBottom = true;
}
void Draw(const char* title, bool* p_open = NULL)
{
ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
ImGui::Begin(title, p_open);
if (ImGui::Button("Clear")) Clear();
ImGui::SameLine();
bool copy = ImGui::Button("Copy");
ImGui::SameLine();
Filter.Draw("Filter", -100.0f);
ImGui::Separator();
ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
if (copy) ImGui::LogToClipboard();
if (Filter.IsActive())
{
const char* buf_begin = Buf.begin();
const char* line = buf_begin;
for (int line_no = 0; line != NULL; line_no++)
{
const char* line_end = (line_no < LineOffsets.Size) ? buf_begin + LineOffsets[line_no] : NULL;
if (Filter.PassFilter(line, line_end))
ImGui::TextUnformatted(line, line_end);
line = line_end && line_end[1] ? line_end + 1 : NULL;
}
}
else
{
ImGui::TextUnformatted(Buf.begin());
}
if (ScrollToBottom)
ImGui::SetScrollHere(1.0f);
ScrollToBottom = false;
ImGui::EndChild();
ImGui::End();
}
};
extern ExampleAppLog* my_log2;
One.cpp
#include ".h"
ExampleAppLog* my_log2 = new ExampleAppLog(); //this line make it crash
void LogHook(const char* Info)
{
my_log2->AddLog(Info);
}
Two.cpp
#include ".h"
bool bDraw = true;
void Draw()
{
my_log2->Draw("Logger", &bDraw);
}
I have tried many different methodes but no luck without it ending up crashing when trying to share a extern object in multiple .cpp.
Logger documentation.
static ExampleAppLog my_log; //have tryd this but with extern etc. It still crash at the same place whan trying to share it globaly. If i do it all in one .cpp out sharing it publicly the code work
[...]
my_log.AddLog("Hello %d world\n", 123);
[...]
my_log.Draw("title");
It is hard to tell you what your problem is because important information is missing.
Are you sure that it crash while checking if Data is a null pointer?
Have you checked if this is valid at the point of crash?
Have you put a breakpoint on the constructor to see when it was called.
While it looks like you don't make any copy of those objects, it would be a good idea to prevent it if not properly supported by deleting copy and move constructor and assignment operators. See https://en.cppreference.com/w/cpp/language/function#Deleted_functions for more information.
One obvious way to see if the problem is that you call a function of ExampleAppLog before it is created is to put a breakpoint inside the constructor. From the above code, we cannot be sure if the class is created only once or multiple times (from elsewhere).
Also are you sure that you don't call Draw or LookHook before you create my_log2 object. Again, that kind of thing is trivial to test with a debugger but very hard for us to tell with only part of the code in our hand. In fact, as the above program does not have a main, it is not a MCVE.
If it really crashes when you are creating ExampleAppLog object and not when trying to use it before it was created, then most of the code above is useless and commenting out code (and remove it from the question) if it still crash, would greatly help people to help you.
On the other hand, if it crash because you are using my_log2 before it is created, then some required code to reproduce the problem is missing.
If the problem is related to initialisation order, then a singleton might be the solution. Look at the accepted answer here: How to implement multithread safe singleton in C++11 without using <mutex>.
In any case, it is hard to help you because you don't put enough effort in your question. Remember that if the code cannot easily be copied and paste, almost nobody will take the time to create a project even more when it is obvious that important lines or information are missing because with the provided information, it is almost impossible that it crash on the specified line.
In fact, in we assume that main is an empty function and that there are no other global usage of either my_log2 pointer and ExampleAppLog struct, then when would the function reserve be called.
As a bonus, if you ask good questions, you get more points on the site!
I am looking for a convenient design in order to be able to use a class on the device which has unknown compile-time size.
Only one instance of this class needs to be sent to the device, for which there should be a single call to cudaMalloc and cudaMemcpy (ideally).
The host version of the class would look like this:
Class A {
public:
A(int size) : table(size) {
// some useful initialization of table
}
double get(int i) const {
// return some processed element from table
}
private:
std::vector<int> table;
};
The kernel:
__global__ void kernel(const A *a){
int idx = threadIdx.x + blockDim.x * blockIdx.x;
a->get(idx); // do something useful with it
}
So far, the way I would design the device version of the class is like that:
const int sizeMax = 1000;
Class A {
public:
A(int size) {
// size checking + some useful initialization of table
}
__host__ __device__
double get(int i) const {
//
}
private:
int table[sizeMax];
};
And the client code:
A a(128);
A* da;
cudaMalloc((void**)&da, sizeof(A));
cudaMemcpy(da, &a, sizeof(A), cudaMemcpyHostToDevice);
kernel<<<1, 32>>>(da);
cudaDeviceSynchronize();
cudaFree(da);
This is rather ugly because:
it wastes bandwith by having to use too large a sizeMax in order to
be on the safe side
the class is not closed for modification, the value of sizeMax will
inevitably need to be raised at some point
Is there any other way to achieve the same thing in a cleaner way without negative performance impact? To be clear, I only need the device version of the class, the first version is just the equivalent non-CUDA code to illustrate the fact that the table size should be dynamic.
In my comment, I said:
separate host and device storage for table, contained in the class, both of which are allocated dynamically. 2. dynamic allocation of table storage size in the constructor, rather than in your client code. This could also include resizing if necessary. 3. differentiation in class methods to use either the host copy of the data or the device copy (i.e. pointer) to the data, depending on whether the method is being executed in host or device code 4. A method to copy data from host to device or vice versa, as the class context is moved from host to device or vice versa.
Here's an example of what I had in mind:
#include <stdio.h>
#include <assert.h>
#include <cuda_runtime_api.h>
#include <iostream>
template <typename T>
class gpuvec{
private:
T *h_vec = NULL;
T *d_vec = NULL;
size_t vsize = 0;
bool iscopy;
public:
__host__ __device__
T * data(){
#ifndef __CUDA_ARCH__
return h_vec;
#else
return d_vec;
#endif
}
__host__ __device__
T& operator[](size_t i) {
assert(i < vsize);
return data()[i];}
void to_device(){
assert(cudaMemcpy(d_vec, h_vec, vsize*sizeof(T), cudaMemcpyHostToDevice) == cudaSuccess);}
void to_host(){
assert(cudaMemcpy(h_vec, d_vec, vsize*sizeof(T), cudaMemcpyDeviceToHost) == cudaSuccess);}
gpuvec(gpuvec &o){
h_vec = o.h_vec;
d_vec = o.d_vec;
vsize = o.vsize;
iscopy = true;}
void copy(gpuvec &o){
free();
iscopy = false;
vsize = o.vsize;
h_vec = (T *)malloc(vsize*sizeof(T));
assert(h_vec != NULL);
assert(cudaMalloc(&d_vec, vsize*sizeof(T)) == cudaSuccess);
memcpy(h_vec, o.h_vec, vsize*sizeof(T));
assert(cudaMemcpy(d_vec, o.d_vec, vsize*sizeof(T), cudaMemcpyDeviceToDevice) == cudaSuccess);}
gpuvec(size_t ds) {
assert(ds > 0);
iscopy = false;
vsize = ds;
h_vec = (T *)malloc(vsize*sizeof(T));
assert(h_vec != NULL);
assert(cudaMalloc(&d_vec, vsize*sizeof(T)) == cudaSuccess);}
gpuvec(){
iscopy = false;
}
~gpuvec(){
if (!iscopy) free();}
void free(){
if (d_vec != NULL) cudaFree(d_vec);
d_vec = NULL;
if (h_vec != NULL) ::free(h_vec);
h_vec = NULL;}
__host__ __device__
size_t size() {
return vsize;}
};
template <typename T>
__global__ void test(gpuvec<T> d){
for (int i = 0; i < d.size(); i++){
d[i] += 1;
}
}
int main(){
size_t ds = 10;
gpuvec<int> A(ds);
A.to_device();
test<<<1,1>>>(A);
A.to_host();
for (size_t i = 0; i < ds; i++)
std::cout << A[i];
std::cout << std::endl;
gpuvec<int> B;
B.copy(A);
A.free();
B.to_device();
test<<<1,1>>>(B);
B.to_host();
for (size_t i = 0; i < ds; i++)
std::cout << B[i];
std::cout << std::endl;
B.free();
}
I'm sure quite a few criticisms could be made. This may not adhere to any particular opinion of what "vector syntax" should be. Furthermore I'm sure there are use cases it does not cover, and it may contain outright defects. To create a robust host/device vector realization may require as much work and complexity as thrust host and device vectors. I'm not suggesting that thrust vectors are a drop-in answer for what the question seems to be asking, however.
Based on Robert Crovella's answer, here is a simplified (device only, so ignoring points 3 & 4) working solution:
Class A {
public:
A(int size) : table(size) {
// some useful initialization of table
cudaMalloc((void**)&dTable, sizeof(int) * size);
cudaMemcpy(dTable, &table[0], sizeof(int) * size, cudaMemcpyHostToDevice);
}
~A() {
cudaFree(dTable);
}
__device__
double get(int i) const {
// return some processed element of dTable
}
private:
std::vector<int> table;
int *dTable;
};
Kernel and client code stay exactly the same.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
So im creating an engine from scrath(learnign purposes).
And when i test my TArray i get an Execption thrown in my Memory.h file. This happens only when im trying to test the TArray
Here is my code for TArray.h
#pragma once
#include "Memory/DynamicLinearStackAllocator.h"
template <typename T, typename Allocator = DynamicLinearStackAllocator>
class TArray
{
private:
Allocator m_Allocator;
uint32 m_ElementCount;
public:
FORCEINLINE TArray()
{
}
FORCEINLINE ~TArray()
{
m_Allocator.Destroy();
}
FORCEINLINE TArray(const uint32 InElementCount)
{
m_Allocator.Resize<T>(InElementCount, m_ElementCount);
m_ElementCount = InElementCount;
}
FORCEINLINE void Add(const T &InValue)
{
}
FORCEINLINE T* GetData() const { return m_Allocator.GetAllocator<T>(); }
FORCEINLINE uint32 Num() const
{
return m_ElementCount;
}
FORCEINLINE T& operator[](uint32 InElementIndex) const
{
check(m_ElementCount > InElementIndex);
return GetData()[InElementIndex];
}
};
namespace Tests
{
FORCEINLINE void TestArrays()
{
{
TArray<float> data(10);
check(data.Num() == 10);
for(uint32 i = 0; i < data.Num(); i++)
{
data[i] = 2.0f;
}
check(data[0] == 2.0f);
}
{
TArray<uint32> data(5);
data[0] = 10;
data[1] = 5;
check(data.Num() == 5);
check(data[0] == 10);
check(data[1] == 5);
}
{
TArray<float> data(1);
data[2] = 2.0f;
}
}
}
When i try to compile(Im using Visual Studio 2017) it gives me an execption error at this position in Memory.h
static void* Copy(void *InDestination, const void *InSource, size_t InSize)
{
check_slow(InDestination);
check_slow(InSource);
check_slow(InSize > 0);
return memcpy(InDestination, InSource, InSize);
}
The test is getting called in the main function with this code:
int main()
{
Tests::TestAssertion();
Tests::TestMemory();
Tests::TestAllocator();
Tests::TestArrays();
return 0;
}
my goal currently is to look if the logger shows me the error here:
{
TArray<float> data(1);
data[2] = 2.0f;
}
here is a screenshot of the full error https://gyazo.com/6c1d6779623ffea97504f5b23f9fd7da
edit: here is the code for the allocator
#pragma once
#include <malloc.h>
#include "Core.h"
#define MEMORY_ALIGMENT 16
struct Memory
{
// TODO:Rework types.
static void* Allocate(const int32 InCount, const size_t InSize)
{
check_slow(InCount > 0);
check_slow(InSize > 0);
const size_t size = InSize * InCount;
return _aligned_malloc(size, MEMORY_ALIGMENT);
}
static void Free(void *InBlock)
{
check_slow(InBlock);
_aligned_free(InBlock);
}
static void* Copy(void *InDestination, const void *InSource, size_t InSize)
{
check_slow(InDestination);
check_slow(InSource);
check_slow(InSize > 0);
return memcpy(InDestination, InSource, InSize);
}
};
void* operator new (size_t InSize)
{
return Memory::Allocate(1, InSize);
}
void operator delete (void* InBlock)
{
Memory::Free(InBlock);
}
namespace Tests
{
struct MemoryTestStruct
{
uint32 p0;
uint32 p1;
uint32 p2;
uint32 p3;
};
FORCEINLINE void TestMemory()
{
MemoryTestStruct *t = new MemoryTestStruct();
check(t);
delete t;
}
}
edit2: Here is the code for the StackAlloctor
#pragma once
#include "../Core.h"
class DynamicLinearStackAllocator
{
private:
void *m_Data;
public:
template <typename T>
FORCEINLINE void Resize(const uint32 InElementCount, const uint32 InPreviousElementCount)
{
void *temp = Memory::Allocate(InElementCount, sizeof(T));
if (InPreviousElementCount > 0)
{
const SIZE_T size = sizeof(T) * InPreviousElementCount;
Memory::Copy(temp, m_Data, size);
Memory::Free(m_Data);
}
m_Data = temp;
}
template <typename T>
FORCEINLINE T* GetAllocator() const
{
return (T*)m_Data;
}
FORCEINLINE void Destroy()
{
Memory::Free(m_Data);
}
};
namespace Tests
{
FORCEINLINE void TestAllocator()
{
DynamicLinearStackAllocator alloc;
alloc.Resize<float>(2, 0);
alloc.Destroy();
}
}
You're not showing the code for your Allocator, but the problem is probably this line in your TArray constructor:
m_Allocator.Resize<T>(InElementCount, m_ElementCount);
At this point, m_ElementCount has not been initialized and will have some random value in it. Resize is then probably trying to free up memory that hasn't been allocated (because of the uninitialized value in m_ElementCount). You should pass in a 0 for the second parameter of the Resize call in your constructor
m_Allocator.Resize<T>(InElementCount, 0);
since there is no existing allocated memory to free.
Also, your default constructor for TArray should initialize m_Allocator.m_data to nullptr (or add a default constructor to DynamicLinearStackAllocator to do that) and set m_ElementCount to 0.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have a application that is suppose to store graphic elements. I am having an issue where I cant access a variable in a structure. Here is what i have so far.
#include <crtdbg.h>
#include <string.h>
#include <stdio.h>
#include "CLib.h"
enum{ RUNNING = 1 };
struct Point
{
int x, y;
};
struct Line
{
Point start;
Point end;
};
struct GraphicElement
{
enum{ SIZE = 256 };
char name[SIZE];
CStash Lines; // a Stash of Lines
};
struct VectorGraphic
{
CStash Elements; // a Stash of GraphicElements
};
void AddGraphicElement(VectorGraphic*);
void ReportVectorGraphic(VectorGraphic*);
void CleanUpVectorGraphic(VectorGraphic*);
VectorGraphic Image;
int main()
{
char response;
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
// it's a Stash of GraphicElements initialize(&(Image.Elements),sizeof(GraphicElement));
while (RUNNING)
{
printf("\nPlease select an option:\n");
printf("1. Add a Graphic Element\n");
printf("2. List the Graphic Elements\n");
printf("q. Quit\n");
printf("CHOICE: ");
fflush(stdin);
scanf("%c", &response);
switch (response)
{
case '1':AddGraphicElement(&Image); break;
case '2':ReportVectorGraphic(&Image); break;
case 'q':CleanUpVectorGraphic(&Image); return 0;
default:printf("Please enter a valid option\n");
}
printf("\n");
}
return 0;
}
void AddGraphicElement(VectorGraphic* pImage){
int i = 0, counter = 0;
int xPointStart = 0, yPointStart = 0;
int xPointEnd = 0, yPointEnd = 0;
char name[50];
int lineNumber = 0;
GraphicElement *pElement = nullptr;
Line *pLine = nullptr;
initialize(&(Image.Elements), sizeof(GraphicElement));
printf("ADDING A Graphic Element\n");
printf("Please enter the name of the new GraphicElement(<256 characters): ");
fflush(stdin);
scanf("\n%[^\n]s", &name);
fflush(stdin);
strcpy(pElement->name,name);
Anytime I try assigning strcpy(pElement->name,name); it tells me access violation.
The two other files im working with that cannot be changed and are from a textbook called Thinking in C++.
//: C04:CLib.cpp {O}
// Implementation of example C-like library
// Declare structure and functions:
#include "CLib.h"
#include <iostream>
#include <cassert>
using namespace std;
// Quantity of elements to add
// when increasing storage:
const int increment = 100;
void initialize(CStash* s, int sz)
{
s->size = sz;
s->quantity = 0;
s->storage = nullptr;
s->next = 0;
}
int add(CStash* s, const void* element)
{
if (s->next >= s->quantity) //Enough space left?
inflate(s, increment);
// Copy element into storage,
// starting at next empty space:
int startBytes = s->next * s->size;
unsigned char* e = (unsigned char*)element;
for (int i = 0; i < s->size; i++)
s->storage[startBytes + i] = e[i];
s->next++;
return(s->next - 1); // Index number
}
void* fetch(CStash* s, int index)
{
// Check index boundaries:
assert(0 <= index);
if (index >= s->next)
return 0; // To indicate the end
// Produce pointer to desired element:
return &(s->storage[index * s->size]);
}
int count(CStash* s)
{
return s->next; // Elements in CStash
}
void inflate(CStash* s, int increase)
{
assert(increase > 0);
int newQuantity = s->quantity + increase;
int newBytes = newQuantity * s->size;
int oldBytes = s->quantity * s->size;
unsigned char* b = new unsigned char[newBytes];
for (int i = 0; i < oldBytes; i++)
b[i] = s->storage[i]; // Copy old to new
delete[](s->storage); // Old storage
s->storage = b; // Point to new memory
s->quantity = newQuantity;
}
void cleanup(CStash* s)
{
if (s->storage != 0)
{
cout << "freeing storage" << endl;
delete[]s->storage;
}
} ///:~
and the .h file...
//: C04:CLib.h
// Header file for a C-like library
// An array-like entity created at runtime
typedef struct CStashTag {
int size; // Size of each space
int quantity; // Number of storage spaces
int next; // Next empty space
unsigned char* storage;// Dynamically allocated array of bytes
} CStash;
void initialize(CStash* s, int size);
void cleanup(CStash* s);
int add(CStash* s, const void* element);
void* fetch(CStash* s, int index);
int count(CStash* s);
void inflate(CStash* s, int increase);
///:~
GraphicElement *pElement = nullptr;
// ...
strcpy(pElement->name,name);
Somewhere between the top line and bottom line above you need to allocate memory for pElement.
pElement = new GraphicElement();
Also, consider using a std::shared_ptr instead of a raw pointer, given you tagged this C++.
I'm using an example code given to me by another C++ coder for a project. I'm a new student of C++ language and I wondered is there a possible memory leak / bugs in this class file given to me (PlacementHead.cpp):
#include "PlacementHead.h"
#include <string>
#include <iostream>
#include <string.h>
PlacementHead::PlacementHead(int width, int height, int gap, char* s) {
width_ = width;
height_ = height;
gap_ = gap;
size_ = (width*height)+1;
set_ = new char[size_ + 1];
from_ = new int[size_ + 1];
original_ = new char[size_ + 1];
strcpy(set_,s);
strcpy(original_,s);
}
PlacementHead::~PlacementHead() {
}
int PlacementHead::getSize() { return size_; }
int PlacementHead::getHeight() { return height_; }
int PlacementHead::getWidth() { return width_; }
int PlacementHead::getGap() { return gap_; }
// Palauttaa indeksissä i olevan suuttimen
char PlacementHead::getNozzle(int i) {
return set_[i-1];
}
// Asettaa indeksissä i olevan suuttimen
void PlacementHead::setNozzle(int i, char c) {
set_[i-1] = c;
}
// Merkitsee suuttimen poimituksi poistamalla sen listasta
void PlacementHead::markNozzle(int i, int bankPos) {
set_[i-1] = ' ';
from_[i-1] = bankPos;
}
// Palauttaa seuraavan poimimattoman suuttimen indeksin
int PlacementHead::getNextUnmarkedPos() {
for (int i=0; i<size_; i++) {
if (set_[i]!=' ') {
return i+1;
}
}
return 0;
}
// Palauttaa suuttimen alkuperäisen sijainnin pankissa
int PlacementHead::getBankPos(int i) {
return from_[i-1];
}
// Plauttaa alkuperäisen ladontapaan suutinjärjestyksen
void PlacementHead::reset() {
//for (int i=0; i<size_; i++) {
// set_[i] = original_[i];
//}
strcpy(set_,original_);
}
// Tulostusmetodi
void PlacementHead::print() {
std::cout << "ladontapaa:\n";
for (int h=height_; h>0; h--) {
for (int w=width_; w>0; w--) {
int i = ((h-1)*width_)+w;
std::cout << getNozzle(i);
}
std::cout << "\n";
}
}
PlacementHead.h:
#ifndef PLACEMENTHEAD_H
#define PLACEMENTHEAD_H
class PlacementHead {
public:
PlacementHead(int size, int rows, int gap, char* s);
~PlacementHead();
int getSize();
int getHeight();
int getWidth();
int getGap();
char getNozzle(int i);
void setNozzle(int i, char c);
void markNozzle(int i, int bankPos);
int getNextUnmarkedPos();
int getBankPos(int i);
void reset();
void print();
private:
char* set_;
int* from_;
char* original_;
int size_;
int width_;
int height_;
int gap_;
};
#endif
I notice that there is dynamic allocation of memory, but I don't see a delete anywhere...is this a problem? How could I fix this if it is a problem?
Thnx for any help!
P.S.
I noticed there is no keyword class used in this example?...Can you define a class like this?
It's impossible to say without seeing the class definition (the
header); if size_, etc. are something like
boost::shared_array, or std::unique_ptr, there is no leak.
If they are simply int*, there is a leak.
Of course, no C++ programmer would write this sort of code
anyway. The class would contain std::vector<int> and
std::string. Judging from what we see here, the author
doesn't know C++.
the code has leak . the constructor allocates the memory .Destructor or some other function have to clean that before the object gets destroyed
Another problem is that your code does not obey Rule of three (links here and here)
once you will write code like:
{
PlacementHead a(0,0,0,"asdsa");
PlacementHead b(0,0,0,"asdsa");
a = b; // line 1
} // here segfault
you will get segfault, in line 1, pointers will be copied from b to a, and once you will finally have destructors, pointers will be deleted twice, which is wrong. This is called shallow copy, you need deep copy, where new array will be allocated.