I've got a huge problem with memory leaks in my program.
I use Valgrind to check memory leaks and with some changes I got about ~20 errors or ~40 errors, but still I can't eliminate all and don't know how.
And I can't change the code in main function, I must fit to it.
I can't change specialisation to string!
Question is what is a properly way to manage with char* and memory.
Rules:
Main code is unchangable
Don't pack char* in any smart pointers or other types.
Problem
Managing memory with char* with containers.
Is it still possible ?
Or instead of container safer is normally allocated array ?
What is wrong with my destructor for char* ?
My main function:
#include <iostream>
#include "test.h"
#include <vector>
using namespace std;
int main()
{
char * cpt[]={"tab","tab2","tab3"};
test<char*> test1;
test1.addItem(cpt[1]);
char * item=test1.getItem(0);
item[0]='Z';
cout<<item<<endl;
return 0;
}
test.h
#ifndef TEST_H
#define TEST_H
#include <vector>
using namespace std;
template<class T>
class test
{
public:
~test();
void addItem(T element){
elements.push_back(element);
}
T getItem(int i){
return elements[i];
}
vector<T> elements;
};
#endif // TEST_H
test.cpp
#include "test.h"
#include <iostream>
#include <cstring>
using namespace std;
template<>
char * test<char*>::getItem(int i)
{
/*char *nowy=new char(strlen(elements[i])+1);
//strcpy(nowy,elements[i]);
return nowy;
//with above code 39 errorr in Valgrind
*/
return elements[i]; // with this instead of above 19 errors in Valgrind
}
template<>
void test<char*>::addItem(char* element){
char * c= new char( strlen (element)+1);
strcpy(c,element);
elements.push_back(c);
}
template<>
test<char*>:: ~test(){
for( auto v: elements)
delete []v; //with this 20 errors
//delete v; instead of above line 19 errors;
}
You should replace
new char(strlen (element) + 1); // this allocate one char with given initial value
by
new char[strlen (element) + 1]; // array of (uninitialized) char
to allocate array of char.
then you have to call delete [].
Related
I tried to make a program to write lists and save them to binary files so nobody can change it and its size less than the text file. I tried to use three vectors inside each other, but when reading it gives a segmentation fault.
Here is the writing code:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
vector<vector<vector<string>>> test;
int main() {
test.push_back({{"Hello"}});
cout << test[0][0][0];
ofstream otst("test.bin",ios::binary);
otst.write((char*)&test,sizeof(test));
return 0;
}
And here is the reading code:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
vector<vector<vector<string>>> test;
int main() {
ifstream tst("test.bin",ios::binary);
tst.read((char*)&test,sizeof(test));
return 0;
}
You are trying to write() and read() the outer vector object exactly as it appears in memory. That will not work, since it contains pointers to data that is stored elsewhere in memory. You must serialize its data instead, and then deserialize it in the reading code, eg:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdint>
using namespace std;
template<typename T>
void write(ofstream &out, const T &value)
{
out.write(reinterpret_cast<const char*>(&value), sizeof(value));
}
void write(ofstream &out, const string &value)
{
uint32_t size = str.size();
write(out, size);
if (size > 0) {
out.write(str.c_str(), size);
}
}
template<typename T>
void write(ofstream &out, const vector<T> &vec)
{
uint32_t size = vec.size();
write(out, size);
for(const auto &elem : vec) {
write(out, elem);
}
}
int main()
{
vector<vector<vector<string>>> test;
test.push_back({{"Hello"}});
cout << test[0][0][0];
ofstream otst("test.bin", ios::binary);
otst.exceptions(ofstream::failbit);
write(otst, test);
return 0;
}
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdint>
using namespace std;
template<typename T>
void read(ifstream &in, T &value)
{
in.read(reinterpret_cast<char*>(&value), sizeof(value));
}
void read(ifstream &in, string &str)
{
uint32_t size;
read(in, size);
str.resize(size);
if (size > 0) {
in.read(&str[0]/* or: str.data() */, size);
}
}
template<typename T>
void read(ifstream &in, vector<T> &vec)
{
uint32_t size;
read(in, size);
vec.resize(size);
for(auto &elem : vec) {
read(in, elem);
}
}
int main()
{
vector<vector<vector<string>>> test;
ifstream itst("test.bin",ios::binary);
itst.exceptions(ifstream::failbit);
read(itst, test);
return 0;
}
UPDATE:
If you can use Boost, it has its own serialization framework, which natively supports serializing vectors. See C++ Boost serialization of a matrix of vectors
I had a similar issue with writing 3d arrays from the heap to memory and reading it. I don't know if it would solve your issue but it's possible that each vector dimension contains a pointer to another vector until the program gets to the base vector so the data that is written is just the pointer of the vectors which would not be part of the program when you read from the binary file. This would result in the program writing pointers to unallocated memory which would cause a segmentation fault. Another possible problem is that you read to sizeof(test) which might not have allocated space for non-existent elements(I haven't worked with vectors a ton so I don't know how stack allocation works with them). My money is on the first idea though which is good because it is also easier to fix. Just right simple recursion in your write process for example:
int main() {
fstream fs;
fs.open("test.bin",ios::out | ios::binary);
vector<vector<vector<string>>> test;
for(int h = 0; h < test[0].size(); h++) {
for(int w = 0; w < test[0][0].size(); w++) {
for(int t = 0; t < test[0][0][0].size(); t++) {
fs.write((char*)&test[h][w][t], sizeof(test));
}
}
}
return 0;
}
I would recommend however, that if you can yous should just use a really large array like a [1000][1000][1000] array. It is easier to use set amounts of numbers.
Anyone know how to Initialise the array of car registration structures by placing a “Empty” in the car registration number of each array element.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <conio.h>
#include <iomanip>
using namespace std;
int main()
{
struct car;
{
string car_reg = 0;
char car_manuf[30];
char car_model[30];
double price;
string car_reg{};
}
}
need some h3elp
Explanation inline.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <conio.h>
#include <iomanip>
using namespace std;
int main()
{
struct car // removed ; the ; terminates the definition, cutting it off
// and leaving you with a declaration. Everything in the braces
// that follow would be seen as a block of code defining two
// automatic variables scoped inside the block. Useless in this
// case.
{
string car_reg = 0; // this is actually NASTY! More on it later
char car_manuf[30] = "EMPTY"; // assigns default value. But only if your
// compiler comes from this decade.
// If you are rocking an antique you can't
// do this. Will cover what you can do below.
char car_model[30] = "EMPTY";
string car_reg{}; // cannot reuse the car_reg identifier in the same scope
// car_reg is either a variable or a function.
}; // ; goes here
car c; // for testing purposes
cout << c.car_manuf << ',' << c.car_model; // for testing
}
string car_reg = 0; is nasty. What it does is defines a member variable car_reg and uses 0 as the default. The 0 is converted to a null pointer to a char array. The string constructor attempts to initialize from a null pointer and blows up at runtime. The compiler is just fine with this bit of stupidity because in the old days NULL could be #define NULL 0 and we don't want to break decades of old code by fixing this problem.
Since we can't do default initializations in pre C++11 code we need a constructor to do the work. Yup. structs can have constructors. This is because a struct and a class are almost identical. The only difference you're ever likely to see between the two is class defaults to private access and structs default to public access.
struct car
{
char car_manuf[30];
char car_model[30];
car (): car_manuf("EMPTY"), car_model("EMPTY")
{
}
};
Note that his isn't as groovy as it looks. You're usually better off with something like
struct car
{
string car_manuf;
string car_model;
car (const string & manuf,
const string & model): car_manuf(manuf), car_model(model)
{
}
};
and not allowing the empty case at all. When possible force users to initialize a class into a fully initialized state. And use std::string. Very handy tool, std::string.
Note that
struct car
{
char car_manuf[30];
char car_model[30];
car (const char * manuf,
const char * model):
car_manuf(manuf), car_model(model) // fails to compile
{
}
};
is not possible. You can't initialize a char array with a pointer to char. I'm not entirely certain why the language doesn't have a rule to handle this, but it doesn't. If forced to use char arrays,
struct car
{
char car_manuf[30];
char car_model[30];
car (const char * manuf,
const char * model)
{
strcpy(car_manuf, manuf);
strcpy(car_model, model);
}
};
and make dang sure that manuf and model will fit in 29 characters or less.
Have you tried a simple for loop, to fill (for example) the char_model array with zeros?
....
char car_model[30];
/* Adding the for loop here (it will fill car_model's elements with zeros*/
for(int i=0; i<=sizeof(car_model); i++){
car_model[i]=0;
....
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <conio.h>
#include <iomanip>
using namespace std;
int main()
{
struct car
{
string car_reg = {"Empty"};
char car_manuf[30];
char car_model[30];
car(const char* manuf,
const char* model)
{
strcpy(car_manuf, manuf);
strcpy(car_model, model);
}
};
}
I want to do this:
Array<int>* arr = new Array();
But I keep getting an error: Argument list for class "Array" is missing.
Is it not possible to create this on the heap? I haven't seen any code that seems to do this.
I've tried another way as well where I use the code:
Array<int>* arr;
and then tried to print the contents of the array, but it was giving me the error that it hadn't been instantiated yet. If I cannot create it on the heap, how am I suppose to instantiate it dynamically. I don't know what the user will want to put into it, after all.
Here's all my code:
Array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_
#include <cstring> // for size_t definition
/**
* #class Array
*
* Basic implementation of a standard array class for chars.
*/
template <typename T>
class Array
{
public:
/// Type definition of the element type.
typedef T type;
/// Default constructor.
Array (void);
private:
/// Pointer to the actual data.
T* data_;
/// Current size of the array.
size_t cur_size_;
/// Maximum size of the array.
size_t max_size_;
};
#include "Array.inl"
//#include "Array.cpp"
#endif // !defined _ARRAY_H_
Array.cpp
#include <stdexcept> // for std::out_of_bounds exception
#include <iostream>
#include "Array.h"
#define MAX_SIZE_ 20
//
// Array
// Default Constructor
template <typename T>
Array <T>::Array (void)
:data_(new T[MAX_SIZE_]),
cur_size_(0),
max_size_(MAX_SIZE_)
{ }
Array.inl
//
// size
//
template <typename T>
inline
size_t Array <T>::size(void) const
{
return this->cur_size_;
}
//
// max_size
//
template <typename T>
inline
size_t Array <T>::max_size(void) const
{
return this->max_size_;
}
driver.cpp
#include <iostream>
//#include "Array_Base.h"
#include "Array.h"
int main(void)
{
Array<int>* arr = new Array();
std::cout << "Max size of array is: " << arr->max_size() << std::endl;
}
Because the class is a template class, just Array isn't a full type. You need to include the template type. And there's no need for the empty parentheses at the end.
Array<int>* arr = new Array<int>;
Bad access means that i am trying to access memory that doesn't exists I have tried and tried to allocate memory for this class, but have failed everywhere. I do not know where the error is actual coming from. It only tells me that my setter method is when the program crashes. In the setFName() method is where the error occurs. But in the main method is where it actually occurrs.
nurse.hpp
#ifndef Nurse_hpp
#define Nurse_hpp
#include <stdio.h>
#include <string>
#include <stdlib.h>
using namespace std;
class nurse{
private:
string firstName;
public:
nurse() {
firstName = "jim";
}
string getFName() {return firstName;}
void setFName(string fName) {firstName = fName;} // Thread 1: bad access 0x0
};
#endif /* Nurse_hpp */
here is where the error is actually happening
main.cpp
#include <cstdint> // ::std::uint64_t type
#include <cstddef> // ::std::size_t type
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include "nurseHolder.hpp"
using namespace std;
nurseHolder *l = new nurseHolder();
int main() {
return 0;
}
and finally here is the class that is causing the issue
nurseHolder.hpp
#ifndef Nurses_hpp
#define Nurses_hpp
#include <stdio.h>
#include <vector>
#include <stdlib.h>
#include "Nurse.cpp"
using namespace std;
class nurseHolder{
private:
int nurse_cnt;
int nurse_cap;
vector<nurse> nurse_list;
public:
nurseHolder() {
nurse_cnt = 0;
nurse_cap = 10;
for(int i= 0; i < 11; i++){
nurse_list[i].setFName("na");
}
}
vector<nurse> &getNurseList() { return nurse_list;}
};
#endif /* Nurses_hpp */
I tried to make this compact as possible sorry if its a lot of code.
here is what I changed to make the code work:
nurseHolder() {
nurse_cnt = 0;
nurse_cap = 10;
for(int i= 0; i < 11; i++){
nurse l;
nurse_list.pushback(l);
}
}
Is this a correct way to do this?
Your vector nurse_list has size 0. So you cannot use [] operator to set names.
There are two ways you can correct this:
Set an initial size to the vector and use [] to set names.
Use push_back to add elements to the vector.
First method.
nurse_list.resize(noOfTotalNurses).
nurse_list[i].setFName("name");
Second method.
nurse tNurse; //local nurse object
tNurse.setFName("name");
nurse_list.push_back(tNurse);
It's probably very basic but I am stuck and simply don't know what the problem is.
The main code is predefined as a task. The goal is to use const as much as possible. The following constructor is just supposed to copy the literal string to the const m_data and that works fine but I am not able to free the memory - it always leaves 1 block. What am I missing?
main.cpp
#include <iostream>
#include "immstring.hpp"
using namespace std;
using namespace Util;
int main()
{
const ImmutableString s1("Hello");
}
immu.hpp
#include <cstring>
namespace Util {
class ImmutableString {
public:
ImmutableString(const char* src);
~ImmutableString();
private:
char* const m_data;
};
}
immu.cpp
#include "immstring.hpp"
#include <iostream>
#include <cstring>
namespace Util
{
ImmutableString::ImmutableString(const char* src)
:m_data{strcpy(new char[strlen(src)+1],src)}{}
ImmutableString::~ImmutableString()
{
delete m_data;
}
}
To leave all array memories blocks you have to use delete like this :
delete[] m_data;
Thanks,
Robin.