I would like some help in returning references to objects created in the heap.
I am reading a book titled Sam's Teach Yourself C++ and in chapter 12, the author introduces returning references to objects on the heap. The example illustrates a memory leak, and the author says that one of the solutions is to declare the object in the calling function and then to pass it to TheFunction() by reference.
This is the example:
// Listing 12.5
// Resolving memory leaks
#include <iostream>
class SimpleCat
{
public:
SimpleCat (int age, int weight);
~SimpleCat() {}
int GetAge() { return itsAge; }
int GetWeight() { return itsWeight; }
private:
int itsAge;
int itsWeight;
};
SimpleCat::SimpleCat(int age, int weight):
itsAge(age), itsWeight(weight) {}
SimpleCat & TheFunction();
int main()
{
SimpleCat & rCat = TheFunction();
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
std::cout << "&rCat: " << &rCat << std::endl;
// How do you get rid of that memory?
SimpleCat * pCat = &rCat;
delete pCat;
// Uh oh, rCat now refers to ??
return 0;
}
SimpleCat &TheFunction()
{
SimpleCat * pFrisky = new SimpleCat(5,9);
std::cout << "pFrisky: " << pFrisky << std::endl;
return *pFrisky;
}
My attempt:
#include <iostream>
class SimpleCat
{
public:
SimpleCat(int age, int weight);
~SimpleCat() {}
int GetAge() { return itsAge; }
int GetWeight() { return itsWeight; }
private:
int itsAge;
int itsWeight;
};
SimpleCat::SimpleCat(int age, int weight):
itsAge(age), itsWeight(weight) {}
SimpleCat* TheFunction(SimpleCat&);
int main()
{
SimpleCat * rCat;
rCat = TheFunction(rCat);
int age = rCat->GetAge();
std::cout << "rCat is " << age << " years old!\n";
std::cout << "rCat: " << rCat << std::endl;
delete rCat;
rCat = 0;
system("PAUSE");
return 0;
}
SimpleCat* TheFunction(SimpleCat& rCat)
{
rCat = new SimpleCat(5, 9);
std::cout << "rCat: " << rCat << std::endl;
return rCat;
}
Second Attempt
#include <iostream>
using namespace std;
class SimpleCat
{
public:
SimpleCat(int age, int weight)
{
}
void setAge(int age)
{
itsAge = age;
}
void setWeight(int wgt)
{
itsWeight = wgt;
}
~SimpleCat() { cout << "Object is being deleted" << endl; }
int GetAge() { return itsAge; }
int GetWeight() { return itsWeight; }
private:
int itsAge;
int itsWeight;
};
//SimpleCat * TheFunction();
SimpleCat& TheFunction(SimpleCat* rCat)
{
rCat = new SimpleCat(5,9);
//pFrisky->setAge(5);
//pFrisky->setWeight(9);
return *rCat;
}
int main()
{
SimpleCat * rCat;
SimpleCat & rCat = TheFunction(&rCat);
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
system("PAUSE");
return 0;
}
This could work (in the sense, compile), but is actually wrong:
SimpleCat TheFunction()
{
rCat = new SimpleCat(5,9);
// do something with rCat if you want
return *rCat;
}
int main()
{
SimpleCat rCat = TheFunction();
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
system("PAUSE");
return 0;
}
Here, you create the new object and return a reference to it to initialize the other object, which is legit, because every C++ class has a copy constructor by default. However, you'll get a memory leak here, because you create new object which is never deleted afterwards.
This can be a better version:
void TheFunction(SimpleCat*& rCat)
{
if (rCat!=NULL) delete rCat;
rCat = new SimpleCat(5,9);
// do something else with rCat if you want
return; //not required
}
int main()
{
SimpleCat * rCat = NULL;
TheFunction(rCat);
int age = rCat->GetAge();
std::cout << "rCat is " << age << " years old!\n";
system("PAUSE");
return 0;
}
Here, you initialize the new pointer by reference(which is also legit). When you declare the pointer, you declare the variable, which has an address, but doesn't have a sensible content yet. You give the reference to that address to your function, so you don't have to return anything. After the function has initialized your reference, you can use it from your main program. No memory will be leaked here, but only as long as all new pointers are initialized with NULL. So potentially this might cause problems too, if your pointer is somehow pointing to a garbage.
The third version (the safest) would be:
void TheFunction(SimpleCat& rCat)
{
rCat.age = 5;
rCat.weight = 9;
}
int main()
{
SimpleCat rCat;
TheFunction(rCat);
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
system("PAUSE");
return 0;
}
There you give the reference to the new object to the function which will initialize it (i.e. assign some values to its members). The object already exists since the moment it's declared (only initialized by garbage by default), so this is also legit. No memory leak here either, because you don't claim memory for any new object.
SimpleCat * rCat;
SimpleCat & rCat = TheFunction(&rCat);
I don't think these lines are going to do what you think they do.
The first line is declaring a variable rCat that is a pointer to a cat, but never constructing a cat to go with it. The second is going to not work because you're declaring the same variable again. (can't have 2 rCat objects).
I'm still not quite sure what you're trying to do, though.
SimpleCat rCat;
TheFunction(&rCat);
and don't do:
rCat = new SimpleCat(...)
In TheFunction, just do the SetAge/SetWeight calls like you have them.
No leaks because you never called new. Of course, TheFunction no longer needs to return anything either because it's just modifying the object that was passed in. I'm not sure if that demonstrates what the author was trying to get to, though.
I think to demonstrate what the author wants, you'd change your TheFunction to be:
void TheFunction(SimpleCat& rCat) {
rCat.SetAge(5);
rCat.SetWeight(9);
}
Related
#include <iostream>
#include <cstring>
#include <string>
class Cd {
private:
const char* performers;
const char* label;
int selections;
double playtime;
public:
Cd(){
int eight = 8;
performers = new char[eight];
label = new char[eight];
label = "Unknown";
performers = "Unknown";
selections = 0;
playtime = 0.0;
}
Cd(const char* performers, const char* label, int selections, double playtime) {
this->performers = new char[strlen(performers)+1];
this->performers = performers;
this->label = new char[strlen(label) + 1];
this->label = label;
this->selections = selections;
this->playtime = playtime;
}
void setLabel(const char* label) {
this->label = label;
}
void setPerformers(const char* performers) {
this->performers = performers;
}
void setSelections(int selections) {
this->selections = selections;
}
void setPlaytime(double playtime) {
this->playtime = playtime;
}
const char* getLabel() {
return label;
}
const char* getPerformers() {
return performers;
}
int getSelections() {
return selections;
}
double getPlaytime() {
return playtime;
}
virtual void Report() {
std::cout << "Performers: " << performers<<std::endl
<<"Label: " <<label<< std::endl
<<"Number of selections: " << selections << std::endl
<<"Play time: " << playtime << std::endl;
}
~Cd() {
delete[] performers;
delete[] label;
}
};
class Classic : public Cd {
private:
const char* primaryWork;
public:
Classic() {
primaryWork = new char[8];
primaryWork = "Unknown";
}
Classic(const char* primaryWork, const char* performers, const char* label, int selections, double playtime) {
this->primaryWork = new char[strlen(primaryWork) + 1];
this->primaryWork = primaryWork;
setLabel(label);
setPerformers(performers);
setSelections(selections);
setPlaytime(playtime);
}
virtual void Report() {
std::cout << "Primary work: " << primaryWork << std::endl<<
"Performers: " << getPerformers() << std::endl <<
"Label: " <<getLabel() << std::endl<<
"Number of selections: " << getSelections() << std::endl
<< "Play time: " << getPlaytime() << std::endl;
}
~Classic() {
delete[] primaryWork;
};
};
int main()
{
Cd c1("Beatles", "Capitol", 14, 35.5);
Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C", "Alfred Brendel", "Philips" , 2, 57.17);
Cd* parent = &c1;
std::cout << "\nUsing object directly:\n";
std::cout << "***************************" << std::endl;
c1.Report();
c2.Report();
std::cout << "\nUsing type cd * pointer to objects:\n";
std::cout << "***************************" << std::endl;
// Call Report() using Cd type pointer created above
parent->Report();
Classic* classic = &c2;
classic->Report();
// Call Report() using Cd type pointer containing Classic object address
return 0;
}
I don't understand what is wrong with the delete keyword. My code is supposed to delete the memory allocation for the array at the end to save memory, but it is not working. The delete_scalar file pops up and the code does not finish executing. The rest of the code is working fine. The big problem is when I build the code the compiler tells me that there are no errors found.
Write
std::string performers;
instead of
const char* performers;
and so on for the other string-like members. Then you can drop the new[] and delete[] entirely. The bug you have is a reassignment of the pointer to some read-only const char[] type "Unknown" which compiles due to the rules of pointer decay.
Using bare pointers for class members also means you need to write constructors, a destructor, and an assignment operator correctly. If you use std::string then you can rely on the compiler-generated ones.
I'm new to the world of C++ (and OOP).
I'm learning about classes and pointers at this moment, but I'm stuck and hope someone can explain to me what I'm missing or should dig deeper into to broaden my understanding.
Example 1 works:
#include <iostream>
#include <string.h>
using namespace std;
class MyClass
{
private:
char* age;
public:
MyClass(const char* initData)
{
age = NULL;
cout << "In default constructor working on pointers" << endl;
age = new char [strlen(initData)+1];
strcpy(age,initData);
//age = initData;
}
~MyClass()
{
cout << "In destructor working on pointers" << endl;
delete [] age;
}
const char* GetAge()
{
return age;
}
};
int main()
{
//MyClass firstClass(10);
//cout << "First attempt: " ;
//cout << firstClass.GetAge() << endl;
MyClass secondClass("A test from B");
cout << "Second attempt: ";
cout << secondClass.GetAge() << endl;
return 0;
}
However This does not work:
#include <iostream>
#include <string.h>
using namespace std;
class MyClass
{
private:
int* age;
public:
MyClass(const int* initData)
{
cout << "In default constructor working on pointers" << endl;
age = new int;
//strcpy(age,initData);
age = initData;
}
~MyClass()
{
cout << "In destructor working on pointers" << endl;
delete age;
}
const int* GetAge()
{
return age;
}
};
int main()
{
MyClass firstClass(10);
cout << "First attempt: " ;
cout << firstClass.GetAge() << endl;
//MyClass secondClass("B");
//cout << "Second attempt: ";
//cout << secondClass.GetAge() << endl;
return 0;
}
I feel that it has to do with the fact that I pass an int to a constant pointer.
And then try to assign a constant from r-value to l-value with the = operator.
Although it think this is permitted, since I say 'const int* initData' and this tells the compiler to keep the data from changing but memory address can change?
So in my understanding, I pass value 10 to the class that makes a pointer in the default constructor, this makes a memory address and stores it in initData.
I then pass the r-value InitData (mem address) to the l-value age pointer, that accepts memory addresses.
If I try with the exact same code, but use char and copy data over in my first example it works...
Can anyone explain to me what I'm missing, Thanks in advance!
Edit:
I Think I found my solution and understand it better.
Could anyone verify that this is correct, or which is the (more) correct form:
Scenario 1:
#include <iostream>
using namespace std;
class MyClass
{
private:
int* age;
public:
MyClass(const int *initData)
{
cout << "In default constructor working on pointers" << endl;
age = new int;
(*age) = (*initData);
}
~MyClass()
{
cout << "In destructor working on pointers" << endl;
delete age;
}
const int* GetAge()
{
return age;
}
};
int main()
{
int aNum = 10;
MyClass firstClass(&aNum);
cout << "First attempt: " ;
cout << *firstClass.GetAge() << endl;
return 0;
}
Or Scenario 2:
#include <iostream>
using namespace std;
class MyClass
{
private:
int* age;
public:
MyClass(const int &initData)
{
cout << "In default constructor working on pointers" << endl;
age = new int;
(*age) = (initData);
}
~MyClass()
{
cout << "In destructor working on pointers" << endl;
delete age;
}
const int* GetAge()
{
return age;
}
};
int main()
{
MyClass firstClass(10);
cout << "First attempt: " ;
cout << *firstClass.GetAge() << endl;
return 0;
}
I Would think solution 2, as that uses reference to memory and thus speeds up the execution?
Thanks for the assistance already, and sorry for the long post...
First: you can not set a const pointer to a non-const pointer, you can circumvent this using a const_cast<int*>(initData) which gets rid of the const-ness of initData when assigning to age.
But i do not think this is what you want to achieve.
So first of all a pointer is just pointing to memory - that memory must therefore be managed by someone else than the pointer. Usually you only need a pointer if you want to reference something or iterate - if you intend to be the owner of that memory you might not want to use a pointer.
Secondly: if you start learning C++ now, try to learnt 'modern' C++ and utilize smart_pointers (see smart pointers form cppreference).
A rule of thumb: if you do not necessarily need a pointer (no need for iteration, direct memory access) use by reference instead.
But bottom line: your example looks like it is not meant to be used with pointers at all. Just store the int value.
class MyClass
{
private:
int age;
public:
// pass by const reference, this is cheap and good practice
MyClass(const int& initData)
{
cout << "In default constructor working on pointers" << endl;
// here the value of initData is actually copied into age
age = initData;
}
And if you really want to try pointers: start with the std::shared_ptr which is a ref-counting pointer easy to use.
Example:
#include <memory>
#include <iostream>
class test
{
private:
std::shared_ptr<int> age;
public:
// cheap and quick const ref
test(const std::shared_ptr<int>& data)
{
age = data;
}
void print()
{
std::cout << *age << std::endl;
std::cout << "Use count: " << age.use_count() << std::endl;
}
};
int main()
{
// here we store the data
int i = 17;
// here we have the shared_ptr
std::shared_ptr<int> p = std::make_shared<int>(i);
// here we pass it to the object
test t(p);
t.print();
return 0;
}
This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 7 years ago.
I have been attempting to create a function getLocation() that utilizes a pointer to return the value of the struct Location declared in the Character class. I was curious as to the problem with my syntax (or my structure). Knowing that the asterisk * should refer to the value, why is it that my function using an ampersand string& Character::getInventory is able to return the value of that particular index (its return does not need to be converted)?
Trying Location& Character::getLocation() {return position; }
when run results in error C2679: binary '<<': no operator found
Nor
Location*
Which cannot be run as there is no conversion.
I read that the following is likely the most proper because it specifies the scope in which the structure resides, but still results in needing and returning a temporary.
Character::Location* const & Character::getLocation() {return &position; }
Any advice or input would be greatly appreciated, thanks in advance.
Below is my main.cpp, which of course will show the hexadecimal address for Location.
#include <iostream>
#include <string>
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::string;
class Character {
private:
string name;
string inventory[4];
public:
struct Location {
int x; int y;
};
Location position;
public:
void Character::setName(string x) { name = x; }
string Character::getName() { return name; }
void Character::setLocation(int x, int y) {
position.x = x; position.y = y;
}
Location* Character::getLocation() {return &position; }
void Character::setInventory(string(&x)[4]) { for (int i = 0; i < 4; ++i) { inventory[i] = x[i]; } }
string& Character::getInventory(int itemNumber) { return inventory[itemNumber]; }
};
void showUser(Character Character);
int main() {
try {
string items[4] = { "Sword", "Shield", "Potion", "Cloak" };
Character CharacterI;
CharacterI.setName("Some Character");
CharacterI.setInventory(items);
CharacterI.setLocation(1, 30);
cout << "\n" << "Retrieving Character Info..." << "\n" << endl;
showUser(CharacterI);
}
catch (std::exception & e) {
cerr << "\nError : " << e.what() << '\n';
}
system("pause");
return 0;
}
void showUser(Character character) {
cout << "Name : " << character.getName() << endl;
cout << "Location : " << character.getLocation() << endl;
for (int i = 0; i < 4; ++i) {
cout << "Inventory " << i + 1 << " : " << character.getInventory(i) << endl;
}
}
Ok, I think I understand the question better now. The reason why getInventory can successfully return a reference while getLocation does not is because getLocation returns a reference to a temporary variable, which is not good. See the link in #NathanOliver's comment for details. Additionally, to paraphrase a previous comment by #Peter Schneider, an * in an expression dereferences a pointer to return a value, while in a declaration it signifies that a variable will be of pointer type. The two usages are more or less opposites of each other. Example:
int* p = new int; //Declares a pointer to int
int x = *p; //Dereferences a pointer and returns an int
What you need to do is create a member variable to hold the Character's location, then set/get from that variable instead of creating temporaries. You did this already for name and inventory, just keep using that same pattern.
Additionally, whenever you use the Location struct outside of the Character class scope, you need to fully-qualify it with Character::Location.
Example:
#include <iostream>
using namespace std;
class Character {
public:
struct Location {
int x;
int y;
};
Location loc;
void SetLocation(int x, int y) {loc.x = x; loc.y = y;}
Location& GetLocation() {return loc;}
};
int main ()
{
Character c;
c.SetLocation(1,42);
Character::Location l = c.GetLocation();
cout << l.x << endl << l.y << endl;
return 0;
}
Output:
1
42
I have a Spieler class and a Verein class with a vector of Spieler members.
Now if I change something of the Players like the Staerke(german for strength) by using a function of this class in the player class it does not automatically change the value for this player.
Here is the code:
#include <vector>
#include<iostream>
#include <string>
using namespace std;
class Spieler
{
public:
void setinformation(int a, string b, string c, int d)
{
ID = a;
Vorname = b;
Nachname = c;
Staerke = d;
}
void getinformation()
{
cout << "ID: " << ID << endl;
cout << "Vorname: " << Vorname << endl;
cout << "Nachname: " << Nachname << endl;
cout << "Staerke: " << Staerke << endl << endl;
}
void setStaerke(int x)
{
Staerke = x;
}
int getStaerke()
{
return Staerke;
}
private:
string Vorname, Nachname;
int Staerke, ID;
};
class Verein
{
public:
void setSpielerListe(vector<Spieler> x)
{
Spielerliste = x;
}
vector<Spieler> getSpielerListe()
{
return Spielerliste;
}
string getVereinsName()
{
return VereinsName;
}
int getVereinsID() const
{
return VereinsID;
}
void setVereinsID(int x)
{
VereinsID = x;
}
int getGesamtstaerke()
{
Gesamtstaerke = 0;
vector<Spieler> b;
b = getSpielerListe();
for (size_t i = 0; i < b.size(); i++)
{
Gesamtstaerke = Gesamtstaerke + b[i].getStaerke();
}
return Gesamtstaerke;
}
void Vereinsinformationen()
{
vector<Spieler> list;
int id;
string vereinsname;
int gesamtstaerke;
id = getVereinsID();
vereinsname = getVereinsName();
gesamtstaerke = getGesamtstaerke();
list = getSpielerListe();
cout << "VereinsID: " << id << endl;
cout << "Vereinsname: " << vereinsname << endl;
cout << "Gesamstaerke: " << gesamtstaerke << endl << endl;
cout << "Spieler: " << endl;
for (size_t i = 0; i < list.size(); i++)
list[i].getinformation();
}
private:
vector<Spieler> Spielerliste;
int VereinsID, Gesamtstaerke;
string VereinsName;
};
vector<Spieler> spieler;
int main()
{
Spieler Spieler1;
Spieler1.setinformation(0, "Peter", "Pan", 10);
spieler.emplace_back(Spieler1);
Verein Team1;
Team1.setSpielerListe(spieler);
Spieler1.setStaerke(20);
Team1.Vereinsinformationen();
cin.get();
return 0;
}
I'm really new into c++ and programming so the code might be terrible.
Guess it has to do with pointers, I'm really not into the concept of storing data in c++, try to get it by trial & error; So how to change the Staerke in a way that it is changed in the Teams Playerlist too?
The problem is you are storing full object in the vector and not pointers. When you run this line:
spieler.emplace_back(Spieler1);
a copy of Spieler1 is made and put in the vector. So modifying it in the main will have no effect in the vector. Also not that you are copying the vector when setting in Verein class.
You should use pointer if this is what you are after or better yet have a function to modify strength from Verein class taking its id and new strength as parameters might be a good idea. Something like this:
void setStaerke(int id, int x)
{
vector<Spieler>::iterator it = Spielerliste.begin();
while (it != Spielerliste.end())
{
if ((*it).GetId() == id)
{
(*it).setStaerke(x);
break;
}
}
}
If you have access to C++11, it could be made more elegantly.
Hereby you pass and store a copy from the vector into the object:
Team1.setSpielerListe(spieler);
Therefore changes to the original vector and the contained objects will not affect the member.
Further, I don't have much experience with emplace_back, but the more usual way to append an object to a std::vector would also append a copy:
spieler.push_back(Spieler1);
Therefore changes to the original object would not affect the object you've appended to the container.
Make sure you better understand when objects are copied.
For reference:
http://en.cppreference.com/w/cpp/container/vector/emplace_back
http://en.cppreference.com/w/cpp/container/vector/push_back
How to pass objects to functions in C++?
I have the following code written in C++:
#include<iostream>
#include<vector>
using namespace std;
class cViews {
string viewName;
double minD;
vector<double> dss;
public:
string minInput1, minInput2;
cViews(string);
cViews();
void setName(string s) { viewName = s; }
string getName() { return viewName; }
void setMinI(string m) { minInput1 = m; }
string getMinI() { return minInput1; }
void setMinD(double d) { minD = d; }
double getMinD() { return minD; }
void addD(vector<double> k){ dss = k; }
vector<double> getD(){ return dss; }
};
cViews::cViews(string str) {
viewName = str;
vector<double> dss = vector<double>();
}
cViews::cViews() {
vector<double> dss = vector<double>();
}
class Obj{
string name;
cViews dist;
public:
Obj(string);
void setName(string s) { name = s; }
string getName() { return name; }
void addDist(cViews k){ dist = k; }
cViews getDist(){ return dist; }
};
Obj::Obj(string str) {
name = str;
cViews dist();
}
void changeViewN(cViews *v, string s){
v->setMinI(s);
}
int main(){
Obj o1("Object1");
cViews v3;
cViews v1("View 1");
v1.setMinI("View 2");
v1.setMinD(1);
o1.addDist(v1);
cout << o1.getName() << " " << o1.getDist().getMinI() << endl;
v3 = o1.getDist();
changeViewN(&v3, "Changed");
cout << o1.getName() << " " << o1.getDist().getMinI() << endl;
return 0;
}
Output is:
Object1 View 2
Object1 View 2
The problem here is I am trying to change the value of an object that was created within another object.
Output should be:
Object1 View 2
Object1 Changed
Any help is greatly appreciated. Thank you.
To change the object and not a copy, ou have to use pointers or references. Else you just copy the object returned from getDist() and thus cant change the original object.
cViews* getDist(){ return &dist; }
...
changeViewN(o1.getDist(), "Changed");
It seems you got a couple of problems, the first few:
cViews::cViews(string str) {
vector<double> dss = vector<double>();
}
viewName isn't initialized, dss is Declared in the function (which is meaningless as it will be scrapped as soon as the function returns).
ps. you would like to change the second line like this:
cout << o1.getName() << " " << o1.getDist().getMinI() << endl;
to
cout << o2.getName() << " " << o2.getDist().getMinI() << endl;
You should really proofread your code ...