I'm trying to create a constructor in which the strings are dynamically allocated. I've looked up dynamically allocated memory several times and watched a video about it, but I'm still not 100% sure if I'm understanding the concept. I'm hoping an example specific to what I'm coding will help me out a bit.
These are the private variables I have in my h file:
string* tableID;
int numSeats;
string* serverName;
With that in mind, could someone tell me how I could dynamically allocate memory for the strings in this constructor?
Table::Table(const string& tableID, int numSeats, const string& serverName) {
}
Finally, I would greatly appreciate it if someone could tell me the purpose of dynamically allocated memory. I've see explanations on what dynamically allocate memory is, but I'm not understanding the use of it. Why use dynamically allocated memory? What are the benefits? What are the drawbacks? Thank you!
EDIT: I'm including the rest of the h file. Note that this wasn't created by me, so I can't make changes to it. I can only adhere to it in the cpp file.
#include <string>
#include "party.h"
using std::string;
class Table {
public:
Table();
Table(const string& tableID, int numSeats, const string& serverName);
~Table();
const string* getTableID() const { return tableID; }
int getNumSeats() const { return numSeats; }
const string* getServerName() const { return serverName; }
void decrementTimer() { timer--; }
int getTimer() const { return timer; }
void setTimer(int duration) { timer = duration; }
const Party* getParty() { return party; }
void seatParty(const Party* newParty);
void clearTable() { party = nullptr; timer = 0; }
private:
string* tableID;
int numSeats;
string* serverName;
int timer;
const Party* party;
};
The easiest way to get what you want is to take advantage of the Member Initializer List as this also solves the problem of having the parameters shadow the member variables of the same name.
Table::Table(const string& tableID,
int numSeats,
const string& serverName):
tableID(new string(tableID)),
numSeats(numSeats),
serverName(new string(serverName))
{
}
Allocation is performed with the new operator. Later you will have to release the dynamically allocated memory with the delete operator. Here is documentation on new and the same for delete.
But the use a pointer requirement is bizarre as storing pointers to string makes everything else you with the class do orders of magnitude more difficult. This may be the point of the assignment, but there are better and less-confusing ways to teach this lesson.
The allocated strings must be released. The C++ idiom of Resource Allocation Is Initialization (What is meant by Resource Acquisition is Initialization (RAII)?) suggests you have a destructor to automate clean-up to ensure that it is done. If you need a destructor, you almost always need the other two members of The Big Three (What is The Rule of Three?) and possibly need to take The Rule of Five into account as well.
Whereas because string observes the Rule of Five for you, you should be able to take advantage of the Rule of Zero and implement no special functions.
M.M raises an excellent point in the comments. The above example is too naive. It is probably all you need for the assignment, but it's not good enough for real code. Sooner or later it will fail. Example of how it fails.
First we replace string with something that can expose the error:
class throwsecond
{
static int count;
public:
throwsecond(const string &)
{
if (count ++)
{
count = 0; // reset count so only every second fails
throw runtime_error("Kaboom!");
}
cout << "Constructed\n";
}
~throwsecond()
{
cout << "Destructed\n";
}
};
int throwsecond::count = 0;
Then a simple class that does basically the above with less frills
class bad_example
{
throwsecond * a;
throwsecond * b;
public:
bad_example(): a(nullptr), b(nullptr)
{
}
bad_example (const string& a,
const string& b)
{
this->a = new throwsecond(a);
this->b = new throwsecond(b);
}
~bad_example()
{
delete a;
delete b;
}
};
and a main to exercise it
int main()
{
cout << "Bad example\n";
try
{
bad_example("", "");
}
catch (...)
{
cout << "Caught exception\n";
}
}
Output:
Bad example
Constructed
Caught exception
We have an object constructed and never destroyed.
Since a default constructor has been defined by Table we can, with a compiler that supports the C++11 or a more recent Standard, take advantage of delegated constructors to force destruction of the partially constructed object because it has been fully constructed by the default constructor.
class good_example
{
throwsecond * a;
throwsecond * b;
public:
good_example():
a(nullptr), b(nullptr) //must be nulled or destruction is dicey
{
}
good_example (const string& a,
const string& b) : good_example() // call default constructor
{
this->a = new throwsecond(a);
this->b = new throwsecond(b);
}
~good_example()
{
delete a;
delete b;
}
};
Output:
Good example
Constructed
Destructed
Caught exception
One construct and one destruct. The beauty of this approach is it scales well and adds nothing to the code that you don't already have. The cost is minimal, a and b get initialized and then assigned as opposed to just initialization. Faster code is useless if it doesn't work.
Full example: https://ideone.com/0ckSge
If you can't compile to a modern standard, you wind up doing something like
the next snippet to make sure everything is deleted. It's main sin is it's ugly, but as you add more classes that must be constructed and destroyed it starts getting unwieldy.
Table::Table(const string& tableID,
int numSeats,
const string& serverName):
tableID(NULL),
numSeats(numSeats),
serverName(NULL)
{
try
{
this->tableID(new string(tableID)),
// see all the this->es? don't shadow variables and you won't have this problem
// miss a this-> and you'll have a really bad day of debugging
this->serverName(new string(serverName))
// more here as required
}
catch (...)
{
delete this->tableID;
delete this->serverName;
// more here as required
throw;
}
}
There is probably a way to improve on this and make it more manageable, but I don't know it. I just use newer standards and value semantics (I'd love it if someone can provide a good link that describes this concept) where possible.
Related
Multiple students can associate with a single Department and single student can
associate with multiple Departments, but there is no ownership between the objects
and both have their own lifecycle. Both can create and delete independently.
WAP in C++ to model the relationships.
I have implemented this code as follows
#include<iostream>
#include<cstring>
using namespace std;
class Student
{
char* name_p;
public:
Student(char *sName)
{
cout<<"Student constructor called\n";
name_p=new char(sizeof(strlen(sName)));
name_p=sName;
}
~Student()
{
cout<<"Student destructor called\n";
delete name_p;
};
char* sName()
{
return name_p;
}
};
class Department
{
char* name_p;
public:
Department(char *dName)
{
cout<<"Department destructor called\n";
name_p=new char(sizeof(strlen(dName)));
name_p=dName;
}
~Department()
{
cout<<"Department destructor called\n";
delete name_p;
}
char* dName()
{
return name_p;
}
};
class Course
{
Student* std_p;
Department* dept_p;
char* courseName_p;
static unsigned int index;
static Course *courseList_p[4];
public:
Course(char* crseName,Student* student,Department* dept)
{
cout<<"Course constructor called\n";
std_p=student;
dept_p=dept;
if(index<4)
{
courseName_p=new char(sizeof(strlen(crseName)));
courseName_p=crseName;
courseList_p[index]=this;
++index;
}
else
{
cout<<"Cannot accomodate any more Course\n";
}
};
~Course()
{
cout<<"Course destructor called\n";
delete courseName_p;
};
static char* findStudent(char *crseName, char* deptName)
{
for(int i=0; i<index; i++)
{
if ( (courseList_p[i]->getCourseName() == crseName) &&
(courseList_p[i]->getDeptName() == deptName) )
{
return(courseList_p[i]->getStdName());
}
}
}
char* getStdName()
{
return std_p->sName();
};
char* getDeptName()
{
return dept_p->dName();
};
char* getCourseName()
{
return courseName_p;
};
};
unsigned int Course::index =0;
Course* Course::courseList_p[4]={0,0,0,0};
int main()
{
int i;
cout<<"\nExample of Association class\n";
cout<<"-----------------------------------\n\n";
cout<<"We have got 4 students\n";
Student *studentNames[4] = {new Student("Meera"), new Student("Moina"), new Student("Teena"), new Student("Mridula")} ;
cout<<"\n";
cout<<"We have got 2 Departments\n";
Department *departNames[2] = {new Department("Mathematics"), new Department("ComputerSceince")} ;
cout<<"\n";
cout<<"Here class Course Associates Student and Department, with a Course name\n";
Course course1("DataStructure",studentNames[0], departNames[1]);
Course course2("Maths",studentNames[3], departNames[0]);
Course course3("Geometry",studentNames[2], departNames[0]);
Course course4("CA",studentNames[1], departNames[1]);
cout<<"\n";
cout<<"Finding a Student using Course and Department\n";
cout<<"Student who has taken Maths Course in Mathematics Department is:"<<Course::findStudent("Maths", "Mathematics")<<endl;
cout<<"\n";
cout<<"Deletion of objects\n\n";
for(i=0;i<4;i++)
{
delete studentNames[i];
}
cout<<"\n";
for(i=0;i<2;i++)
{
delete departNames[i];
}
cout<<"\n";
return 0;
}
The code is showing warnings in main function i.e. ISO C++ forbids converting a string constant to char* and also the main() function is not returning 0 but a garbage value. Please help me in rectify these errors and warnings.
Also I don't want to use this pointer in class course, can I implement the code without using this pointer.
There are a couple of problems with your code. Mostly they are related to the use of char* instead of string. I'm amazed to see that some teacher still are found of this practice.
c-string allocation problems
The first problem causes memory corruption. This could explain that your main() returns garbage instead of 0. For example:
name_p=new char(sizeof(strlen(dName))); // OUCH!!!
In the statement you allocate it wrong. If you want to allocate an array, you must use new[...]. Moreover, keep in mind that a c-string allways needs 1 char more for the trailing null. So it should be:
name_p=new char[strlen(dName)+1];
would already improve the situation.
Last but not the least, if you allocate an array you must delete an array with delete[]
c-string copying issue
Then, you can copy C++ string with an assignment operator just as in:
name_p=sName; // OUCH
However, for char*, this just overwrites the pointer that new returned and you are not sure that the c-string it points to will still be valid when it's used.
If you want to assign a c-string, you need to go for:
strcpy (name_p, sName); // C-style
copy (sName, sName+strlen(sName)+2, name_p); // Safer C++ alternative
c-string comparison issue
Suppose you have two pointers to c string, say pa and pb. Comparing the pointers looks at the memory address, not at the content. So yu could have two identical strings but the comparison could nevertheless fail. THis kind of comparison would work perfectly well for c++ string, but for cstring, you need to to
strcmp(pa, pb)==0 // instead of pa == pb
c-strings in classes and structures
Whenever you have some pointers that you allocate in a class, you need to think of the rule of 3. Meaning that you'd need to add a copy constructor and an assignment operator. Fortunately, at first sight it seems that you don't need them here. Of couse, if you'd use c++ string you wouldn't have to worry about such details.
c-string conversion issues?
ANother issue in your code is the use of string literals with constructors. For example:
new Student("Meera").... // c-string literals (constant)
Student(char*...) // constructor using a c-string pointer (non constant)
You can easily get rid of this complaint, by making the constructor's pointer argument as constant:
Student(const char *sName)...
The same applies to function arguments, such as in find.
Other problems
The static member findStudent() works well, but only if a result is found. If nothing is found, it's UB, since there is no return statement (put a return nullptr; at the end of this function?)
Moreover, the wya you use this function, directly printing its result is dangerous, because dereferencing an invalid pointer will lead to UB.
Here the corrected code. It compiles and seem to run. I didn't analyse for more issues.
The problem
I am writing a thin C++ wrapper around an object oriented C library. The idea was to automate memory management, but so far its not been very automatic. Basically when I use my wrapper classes, I get all kinds of memory access and inappropriate freeing problems.
Minimal example of C library
Lets say the C library consists of A and B classes, each of which have a few 'methods' associated with them:
#include <memory>
#include "cstring"
#include "iostream"
extern "C" {
typedef struct {
unsigned char *string;
} A;
A *c_newA(const char *string) {
A *a = (A *) malloc(sizeof(A)); // yes I know, don't use malloc in C++. This is a demo to simulate the C library that uses it.
auto *s = (char *) malloc(strlen(string) + 1);
strcpy(s, string);
a->string = (unsigned char *) s;
return a;
}
void c_freeA(A *a) {
free(a->string);
free(a);
}
void c_printA(A *a) {
std::cout << a->string << std::endl;
}
typedef struct {
A *firstA;
A *secondA;
} B;
B *c_newB(const char *first, const char *second) {
B *b = (B *) malloc(sizeof(B));
b->firstA = c_newA(first);
b->secondA = c_newA(second);
return b;
}
void c_freeB(B *b) {
c_freeA(b->firstA);
c_freeA(b->secondA);
free(b);
}
void c_printB(B *b) {
std::cout << b->firstA->string << ", " << b->secondA->string << std::endl;
}
A *c_getFirstA(B *b) {
return b->firstA;
}
A *c_getSecondA(B *b) {
return b->secondA;
}
}
Test the 'C lib'
void testA() {
A *a = c_newA("An A");
c_printA(a);
c_freeA(a);
// outputs: "An A"
// valgrind is happy =]
}
void testB() {
B *b = c_newB("first A", "second A");
c_printB(b);
c_freeB(b);
// outputs: "first A, second A"
// valgrind is happy =]
}
Wrapper classes for A and B
class AWrapper {
struct deleter {
void operator()(A *a) {
c_freeA(a);
}
};
std::unique_ptr<A, deleter> aptr_;
public:
explicit AWrapper(A *a)
: aptr_(a) {
}
static AWrapper fromString(const std::string &string) { // preferred way of instantiating
A *a = c_newA(string.c_str());
return AWrapper(a);
}
void printA() {
c_printA(aptr_.get());
}
};
class BWrapper {
struct deleter {
void operator()(B *b) {
c_freeB(b);
}
};
std::unique_ptr<B, deleter> bptr_;
public:
explicit BWrapper(B *b)
: bptr_(std::unique_ptr<B, deleter>(b)) {
}
static BWrapper fromString(const std::string &first, const std::string &second) {
B *b = c_newB(first.c_str(), second.c_str());
return BWrapper(b);
}
void printB() {
c_printB(bptr_.get());
}
AWrapper getFirstA(){
return AWrapper(c_getFirstA(bptr_.get()));
}
AWrapper getSecondA(){
return AWrapper(c_getSecondA(bptr_.get()));
}
};
Wrapper tests
void testAWrapper() {
AWrapper a = AWrapper::fromString("An A");
a.printA();
// outputs "An A"
// valgrind is happy =]
}
void testBWrapper() {
BWrapper b = BWrapper::fromString("first A", "second A");
b.printB();
// outputs "first A"
// valgrind is happy =]
}
Demonstration of the problem
Great, so I move on and develop the full wrapper (lot of classes) and realise that when classes like this (i.e. aggregation relationship) are both in scope, C++ will automatically call the descructors of both classes separately, but because of the structure of the underlying library (i.e. the calls to free), we get memory problems:
void testUsingAWrapperAndBWrapperTogether() {
BWrapper b = BWrapper::fromString("first A", "second A");
AWrapper a1 = b.getFirstA();
// valgrind no happy =[
}
Valgrind output
Things I've tried
Cloning not possible
The first thing I tried was to take a copy of A, rather than having them try to free the same A. This, while a good idea, is not possible in my case because of the nature of the library I'm using. There is actually a catching mechanism in place so that when you create a new A with a string its seen before, it'll give you back the same A. See this question for my attempts at cloning A.
Custom destructors
I took the code for the C library destructors (freeA and freeB here) and copied them into my source code. Then I tried to modify them such that A does not get freed by B. This has partially worked. Some instances of memory problems have been resolved, but because this idea does not tackle the problem at hand (just kind of temporarily glosses over the main issue), new problems keep popping up, some of which are obscure and difficult to debug.
The question
So at last we arive at the question: How can I modify this C++ wrapper to resolve the memory problems that arise due to the interactions between the underlying C objects? Can I make better use of smart pointers? Should I abandon the C wrapper completly and just use the libraries pointers as is? Or is there a better way I haven't thought of?
Thanks in advance.
Edits: response to the comments
Since asking the previous question (linked above) I have restructed my code so that the wrapper is being developed and built in the same library as the one it wraps. So the objects are no longer opaque.
The pointers are generated from function calls to the library, which uses calloc or malloc to allocate.
In the real code A is raptor_uri* (typdef librdf_uri*) from raptor2 and is allocated with librdf_new_uri while B is raptor_term* (aka librdf_node*) and allocated with librdf_new_node_* functions. The librdf_node has a librdf_uri field.
Edit 2
I can also point to the line of code where the same A is returned if its the same string. See line 137 here
The problem is that getFirstA and getSecondA return instances of AWrapper, which is an owning type. This means that when constructing an AWrapper you're giving up the ownership of an A *, but getFirstA and getFirstB don't do that. The pointers from which the returned objects are constructed are managed by a BWrapper.
The easiest solution is that you should return an A * instead of the wrapper class. This way you're not passing the ownership of the inner A member. I also would recommend making the constructors taking pointers in the wrapper classes private, and having a fromPointer static method similar to fromString, which takes ownership of the pointer passed to it. This way you won't accidently make instances of the wrapper classes from raw pointers.
If you want to avoid using raw pointers or want to have methods on the returned objects from getFirstA and getSecondA you could write a simple reference wrapper, which has a raw pointer as a member.
class AReference
{
private:
A *a_ref_;
public:
explicit AReference(A *a_ref) : a_ref_(a_ref) {}
// other methods here, such as print or get
};
You are freeing A twice
BWrapper b = BWrapper::fromString("first A", "second A");
When b goes out of scope, c_freeB is called which also calls c_freeA
AWrapper a1 = b.getFirstA();
Wraps A with another unique_ptr, then when a1 goes out of scope it will call c_freeA on the same A.
Note that getFirstA in BWrapper gives ownership of an A to another unique_ptr when using the AWrapper constructor.
Ways to fix this:
Don't let B manage A memory, but since you are using a lib that won't be possible.
Let BWrapper manage A, don't let AWrapper manage A and make sure the BWrapper exists when using AWrapper. That is, use a raw pointer in AWrapper instead of a smart pointer.
Make a copy of A in the AWrapper(A *) constructor, for this you might want to use a function from the library.
Edit:
shared_ptr won't work in this case because c_freeB will call c_freeA anyways.
Edit 2:
In this specific case considering the raptor lib you mentioned, you could try the following:
explicit AWrapper(A *a)
: aptr_(raptor_uri_copy(a)) {
}
assuming that A is a raptor_uri. raptor_uri_copy(raptor_uri *) will increase the reference count and return the same passed pointer. Then, even if raptor_free_uri is called twice on the same raptor_uri * it will call free only when the counter becomes zero.
I am having issues with trying to figure out how I would turn a data member inside a class (which was originally an int) into a pointer to a dynamically allocated piece of memory.
I know I can do int *num = new int under normal circumstances, but how would I initialize it in a class?
My teacher did an amazing job of not explaining this in the crappiest way possible in class -_-.
This is an example of the class and the constructor.
The header
class Double
{
private:
double *val;
The .cpp
Double::Double()
{
this->equals(0.0);
}
Double::Double(const Double &d)
{
this->equals(d.val);
}
Double::Double(const double &d)
{
this->equals(d);
}
Double::Double(const Interger &i)
{
this->equals(i.toInt());
}
//New overloaded constructor using strings
Double::Double(const string &s)
{
this->equals(s);
}
void Double::equals(const double &d)
{
this->val = d;
}
All I know is I have to make the data member a pointer now, but I have no idea how to create the new memory. I tried looking this up but I could not find an example of how to do DAM inside an actual class for its memory and constructor.
EDIT
Solution was a simpler then I thought.
Double::Double() : val(new double)
{
......
}
just have to do that to every constructor, then change any instance of d.val or this->val to *d.val or *this->val.
SOLUTION TO MY PROBLEM (So the problem is solved)
Solution was simpler then I thought.
Double::Double() : val(new double)
{
......
}
just have to do that to every constructor, then change any instance of d.val or this->val to *d.val or *this->val.
Deconstructors will have to be created to clear the memory though.
Say I have a class:
class A
{
private:
const int * const v;
public:
A();
}
I want v to be allocated in the initialization list, and I think I can define the following constructor:
A::A():v((int*)malloc(10*sizeof(int))){}
However, what about v has to be allocated in a non-standard way like the following:
cudaMalloc(&v,10*sizeof(int));
Note cudaMalloc is a CUDA API to allocate GPU memory.
(Ignoring the bigger-picture matters of overall design, exception safety etc. and focusing on the question in its most narrow scope)
Abandon the idea of doing in the initializer list and do it in the constructor body instead
A::A() : v(NULL)
{
cudaMalloc(&v, 10 * sizeof(int));
}
Or, alternatively, wrap the allocation function into your own function that returns the pointer
void *wrapped_cudaMalloc(size_t size)
{
void *m = NULL;
cudaMalloc(&m, size);
return m;
}
...
A::A() : v(wrapped_cudaMalloc(10 * sizeof(int)))
{}
Just for the sake of completeness, there's also an ugly convoluted way to do it in the initializer list without creating any wrappers by exploiting the properties of , operator
A::A() : v((cudaMalloc(&v, 10 * sizeof(int)), v))
{}
Note the additional pair of () around the comma-expression, which is needed to satisfy the initialization syntax (otherwise , will be treated as argument separator instead of comma operator).
In addition to AndreyT's excellent post (and his creative use of the comma operator), you could also wrap things up thusly:
class cudaMallocedInt
{
private:
int *v;
public:
cudaMallocedInt(int n)
{
cudaMalloc(&v, n * sizeof(int));
}
cudaMallocedInt(const cudaMallocedInt &o)
{
// Do whatever is appropriate here. Probably some sort of dance.
}
~cudaMallocedInt()
{
// Remember to cudaFree or whatever
}
operator int*()
{
return v;
}
};
class A
{
private:
cudaMallocedInt v;
public:
A()
: v(10)
{
}
...
};
Update: As Johnsyweb pointed out in comments, please be sure to adhere to the Rule of Three to make sure things don't go boom and you waste your weekends tracking down hard to debug errors instead of having fun!
I'm quite new to C++ and I am trying to store objects inside a std::vector like this:
Event.h:
//event.h
class Event
{
public:
Event();
Event(std::string name);
~Event();
void addVisitor(Visitor visitor);
private:
std::vector<Visitor> m_visitors;
};
Event.cpp:
//event.cpp
Event::Event() :
m_name("Unnamed Event")
{
}
Event::Event(std::string name) :
m_name(name)
{
}
void Event::addVisitor(Visitor visitor)
{
this->m_visitors.push_back(visitor);
}
void Event::listVisitors()
{
std::vector<Visitor>::iterator it;
for(it = this->m_visitors.begin();it != this->m_visitors.end(); ++it)
{
std::cout << it->getName() << std::endl;
}
}
Visitor.h:
//visitor.h
class Visitor
{
public:
Visitor();
Visitor(std::string name);
~Visitor();
std::string getName() const;
void listVisitors();
private:
std::string m_name;
};
Visitor.cpp:
//visitor.cpp
Visitor::Visitor() :
m_name("John Doe")
{
}
Visitor::Visitor(std::string name) :
m_name(name)
{
}
std::string Visitor::getName() const
{
return m_name;
}
main.cpp:
//main.cpp
int main()
{
Event *e1 = new Event("Whatever");
Visitor *v1 = new Visitor("Dummy1");
Visitor *v2 = new Visitor("Dummy2");
e1->addVisitor(*v1);
e1->addVisitor(*v2);
}
If I do it like this I would have to add a copy constructor which would make a deep copy so the object gets copied properly into the vector. I'm looking for a way around it by only storing pointers to the objects in a vector.
I already tried it with std::vector<std::unique_ptr<Visitor> > m_visitors, but then I got some errors when calling addVisitor in main.cpp. Of course I changed the declaration of the class members accordingly.
How would an appropriate declaration of the members and the member function look like to make it work?
Stylistically, if you are passing pointers, just accept pointers as the function arguments.
What's happening in the example code above is that the visitors are getting copied to become function arguments and the pointers you had are unreferenced by anything outside of the main function.
I can't speak to what the errors are that you're seeing as you didn't describe them but it probably has to do with incompatible types.
Just get rid of the news because for these data structures they're unnecessary.
int main()
{
Event e1("Whatever");
Visitor v1("Dummy1");
Visitor v2("Dummy2");
e1.addVisitor(v1);
e1.addVisitor(v2);
}
I would suggest that if you don't know how to use pointers you couldn't possibly want to store them instead (they're a hassle IMO to store in the vector when copying by value works just fine).
The compiler generated copy constructor should work just fine.
No manual deep copy required, because you are quite correctly using std::string, which supports RAII.
However, your main function has three memory leaks — there is no need to use new there anyway, so simply don't.
General rule of thumb:
If, at any time T, you're thinking of introducing more pointers into your code, then you're probably going in the wrong direction.