Class' methods and objects. Reference? Smart pointers? Simple initialization? - c++

I've been delving into the referenciation and smart pointers over the last couple of days and I still can't figure out when to use which.
Especially for the very simple program I am trying to write.
Where the object value shouldn't be shared but only modified trought returning a value of its type from X or Y methods.
If I am not mistaken, references are easier on the memory, but refers only to one thing.
Where as smart pointers are more stable and can be remaped to point at something else.
First Question:
For simple alterations to an object like in the example bellow, is it even necessary to create a reference or a pointer?
I suppose that in the long run, as the program adds in complexity, having but initialized objects doing their thing could create latency issues and the likes...
Second Question:
As I understand it, refering to an object will aleviate the stress on the memory by refering to the object when used as a parameter in the method instead of copy-pasting the object into it?
Does a smart_ptr does the same-ish?
The header file for class:
-Items.h-
class Health_Potion
{
public:
int qty = 0;
static int add_health_potion(int current, int add);
};
The cpp file for methods:
-Items.cpp-
int Health_Potion::add_health_potion(int current, int add)
{
int new_current = current + add;
cout << add << " potion added to your inventory.\n";
cout << "Quantity available: " << new_current << "\n";
return current + add;
}
The main function:
-Main-
int main()
{
// Initializing the method to be used:
// Question: Should this also be stored into a smart_ptr or referenced to?
Health_Potion add_method;
add_method.add_health_potion;
______________________________________________
// The unique_ptr version I got:
std::unique_ptr<Health_Potion> entity(new Health_Potion); //Unique_ptr
entity -> qty = add_method.add_health_potion(rentity -> qty, roll); //returning new value to the pointer through method
______________________________________________
//The reference version I got:
Health_Potion obj1;
int & refqty = obj1.qty; //reference to object of qty created
refqty = add_method.add_health_potion(refqty, roll); //returning new value to the reference through method
}
Forgive my newbieness.
And thank your for your time :).

I still can't figure out when to use which.
When in doubt, use the simplest approach. Only when the simplest approach is inadequate or awkward is there a reason to consider something more complicated (and at that point, you have a starting point for figuring out which to use).

Related

C++ why cannot assign an object created inside constructor?

due project's requirements, by this week I'm shifted from Java to C++. I'm facing a lot of trouble, but maybe the greater is the "pass-by-value" and... obviously pointers :)
Now I have a big doubt regard the destiny of an object instantiated inside an the constructor of another object. Here my simple SSCCE composed by an header and a cpp file:
#pragma once
#include <map>
class MapReferenceHolder
{
std::map<int, char*>* mapPointer;
public:
MapReferenceHolder();
~MapReferenceHolder();
void setMap(std::map<int,char*>* map);
void addSomeElementToMap();
void MapReferenceHolder::printMap();
};
Here the cpp file containing the main:
#include "MapReferenceHolder.h"
#include <iostream>
using namespace std;
std::map<int, char*>mymap;
MapReferenceHolder::MapReferenceHolder()
{
setMap(&mymap);
}
MapReferenceHolder::~MapReferenceHolder()
{
}
void MapReferenceHolder::setMap(std::map<int, char*>* map){
mapPointer = map;
}
void MapReferenceHolder::addSomeElementToMap(){
(*mapPointer)[0] = "stringONe";
(*mapPointer)[1] = "stringTwo";
}
void MapReferenceHolder::printMap(){
std::map<int, char*>::iterator it = mapPointer->begin();
while (it!=mapPointer->end()){
cout << it->first << " -> " << it->second << "\n";
it++;
}
}
int main(){
MapReferenceHolder m;
m.addSomeElementToMap();
m.printMap();
cin.get();
return 0;
}
This simple example run without problem. But if I move the mymap instantiation inside the constructor, i.e.
MapReferenceHolder::MapReferenceHolder()
{
std::map<int, char*>mymap;
setMap(&mymap);
}
I get thw folowing error:
Unhandled exception at 0x00B2BD3B in Project1.exe: 0xC0000005: Access violation reading location 0xCCCCCCD0.
I guess this is due to the fact that an instance of an object live only inside the block in which is defined. But I'm passing the address of object, so it is still alive!?? Or the compiler destroy it in any case? And more important... is it, then, right create a global variable to store an object instance. How I can use correctly the constructor? I know this is a "newbie" question but I'm try to match project's development needs and my spare time to study is really little. Any help will be great appreciated.
Regards,
microvo
The object is destroyed at the end of the constructor. so you have saved a pointer that is no longer valid.
You need to consider ownership in C++ (Java has a cycle detecting garbage collector so gives you a lot of leeway).
If MapReferenceHolder owns the std::map you should make it a value rather than a pointer, you can always use a reference to it if you need a pointer for some reason. Also get rid of your constructor and destructor unless they contain actual code.
Alternatively you could call delete mapPointer in your destructor but that is adding extra code for no benefit in simple cases like this IMO.
If MapReferenceHolder does not own std::map then you need to require the pointer be passed in and somehow track the lifetime of it somewhere outside this class.
The map object no longer exists once it goes out of scope, regardless of any pointers that hold its address - these are no longer valid. I suggest a search for "constructor initializer list" might help you.

Difference between call by pointer and returning pointer

Is there any difference calling by pointer or returning pointer in following code?
I just try to modify my struct and get the resutl.Lest say I have a struct.
struct Address
{
const char* name; // "Jim Dandy"
int number; // 61
};
Address* Modifying2(Address* adr)
{
adr->name="Long John2";
return adr;
}
//or
void Modifying3(Address* adr)
{
adr->name="Long2 John2";
// return adr; no return
}
void print_addr2(const Address& r)
{
cout << r.name << '\n'
<< r.number << ' ' << r.street << '\n';
}
int main()
{
Address jd =
{
"Jim Dandy",
61
};
Address* jdPtr=&jd;
Modifying3(jdPtr);
print_addr(jdPtr);
//or
print_addr(Modifying2(jdPtr));
return 0;
}
Result is same but Which one is more safe? I mean well defined?
Both methods are doing the same thing. Returning the pointer is not essential.
But the most safest way is to pass the value by reference. (You haven't implement this way). Here how you must do it
void Modifying4(Address &adr)
{
adr.name="Long2 John2";
}
The only reason to return a pointer in the above example is if you want to allow chaining of calls:
Modifying2(Modifying2(jdPtr));
Which, for this particular implementation, does not make much sense since the function simply sets a value to a constant.
In all other cases, returning void is probably preferable, as you do not gain anything by returning the very same pointer that was passed in originally.
There is no real difference. Both work.
But be careful with pointers! If you assign a string longer than the init-value, you have to realloc the space the pointer is pointing to!!!!
mfg
Returning a pointer after modifying the value it points to is redundant.
In the real world other people, like us, or fellow coders in your company will be spending a lot of time in your code.
I forget who said it but you will also be spending 90% of your time pouring through someone else`s code.
If I saw your function that takes and returns a pointer at work I would be very confused why you did it, and it seems to show a lack of understanding of how pointers work and why you would pass a pointer to a function in the first place.
Don`t do it.

C++ can't establish communication between variables in separate functions

I am making a text-based RPG with C++ and I'm having the same error pop up time and again, and I'm sure I'm doing something fundamentally wrong, but I don't know what. Searches turned up the solution to the specific compiler error, but not anything I can use to fix the code I'm writing.
Question I want answered: How do I use pointers to enable communication of variables between separate functions? In other words, how can I use pointers to point to a variable's value so that I can use and manipulate that value in a function in which it was not declared?
TL;DR version: I'm trying to make my "exp" int variable communicate with outside functions using pointers. I get the error "ISO C++ forbids comparison between pointer and integer [-fpermissive]"
Long version: Here's a bit of the code where I'm having problems:
In file charlvl.cpp:
...
int lvl = 1;
int *exp = 0;//value I want communicated to main()
int str = 0;
int vit = 0;
...
in file fight.cpp (main.cpp):
...
//you've just killed a monster
cout << "\nThe monster drops to the ground." << endl;
cout << "You gained " << expValue << " experience!" << endl;
&exp += expValue;//&exp is the character's experience.
//expValue is the exp gained upon monster death
//*exp (from charlvl.cpp) is the value I want to communicate to here.
It was not declared here, but in charlvl.cpp. How do I establish communication between the declared variable in charlvl.cpp and main() without having to resort to using global variables?
If you defined exp as a global pointer, you don't need to think about the communication thing, you can just simply use it in different functions, but the way you use it is wrong.
&exp += expValue;
should be change to
*exp += expValue;
because * means get that pointer's content to me.
btw, try not defining exp as a pointer may also work.
int exp = 0;
exp += expValue;
This is all based on exp is a global var or global pointer.
if you have defined it in a function like this:
void func()
{
int *expPtr = 0;
int exp = 0
}
And you want to use it in another function
void use()
{
// trying to use expPtr or exp.
}
The ways I know is:
1, use a local var and return it in func(), but be aware that the returned var is only a copy.
int func()
{
int exp = 0;
exp++;
return exp;
}
2, use a local pointer and allocate memory for it, then return the pointer or assign the new memory to a global pointer. But be careful about the memory leak, you need to delete it as soon as you don't use it.
int * func()
{
int *expPtr = 0;
expPtr = new int(2);
return expPtr;
}
You've gotten the & and * operators confused. * turns an int* into an int, while & turns an int* into an int**.
This is what you want:
(*exp) += expValue;
You might want to consider using references.

C++ Taking address of temporary - error while assigning reference to pointer

This program is written in C++. I am trying to use a void function to expand a Line structure which consists of an integer length and a pointer to the next connected line. There is a void Expand function made to assign a line reference to the line pointer in the struct. The new line is to be double the size of the current line. With the code I am using, I get a g++ error of 'Taking address of temporary [-fpermissive]'. Could anyone suggest a way in which the function adds a valid instance of a line reference to the Line pointer nextLine?
struct Line
{
int length;
Line* nextLine;
};
Line NewLine(Line& lineRef)
{
Line newLine;
newLine.length = lineRef.length * 2;
return newLine;
}
void Expand(Line& lineRef)
{
//Error here states: Taking address of temporary [-fpermissive]
lineRef.nextLine = &NewLine(lineRef);
}
int main() {
Line line;
Expand(line);
cout << line.length << endl;
cout << line.nextLine->length << endl;
return 0;
}
You're trying to implement a linked list, but you don't understand manual memory management yet.
The short-term solution is to use std::list<Line>. There's already a solution that works, and you don't need to bother with the behind-the-scenes stuff.
The long-term solution also is to use std::list<Line>. No need to re-invent the wheel, even if you're a seasoned developer and know how to.
The problem with the line:
lineRef.nextLine = &NewLine(lineRef);
is what the compiler is telling you. You are taking the address of a temporary. What it means is that after the ; is reached, the temporary NewLine(lineRef) will be destroyed and the pointer lineRef.nextLine will be pointer to a dead object.
Update: how to make it work.
It depends on what you want to do. If what you want is to have a list then the simplest thing is using a prepacked list data structure (std::list<Line>) rather than rolling your own implementation of list.
If you really want to implement your own list, then you will need to dynamically allocate the next node (this will make the compiler happy) and you will need to add code to manage the list (proper construction of the Line object that initializes the fields, including copy-construction, destructors to manage the dynamic memory, probably some helper functions to walk the list (or iterators to be able to use algorithms...) Just don't bother and use std::list.
This one works
struct Line
{
int length;
Line* nextLine;
~Line(){delete nextLine;}
//Make copy constructor and assignment operator private
};
void Expand(Line* lineRef)
{
lineRef->nextLine = new Line;
lineRef->nextLine->length = 2*(lineRef->length) ;
}
int main()
{
Line* line = new Line;
line->length = 5;
Expand(line);
cout << line->length << endl;
cout << line->nextLine->length << endl;
delete line;
return 0;
}

Cannot set pointer location to that of another pointer's location in C++

I have a method that takes in a reference to a vector that contains pointers to objects as the first parameter, and a reference to a pointer to an object of the same type as the second parameter. Within the method, I want to change the location referenced by the second argument to an object within the vector. Then have the changed pointer be used by the caller of the method, having the new location as its target. However, my current attempts at implementing this are failing.
The method in question:
void execute(std::vector<CanvasElement*>& elements,CanvasElement*& lastFocused)
Examples of ways I've unsuccessfully tried setting the value pointed to by lastFocused:
lastFocused = elements[0];
*lastFocused = *elements[0];
An elaboration in reply to a comment below:
The failure is that the changes inside the function are not reflected once outside the scope of that function.
I can confirm by printing the addresses stored in each pointer during the application's runtime, that the value is indeed being set within execute, but outside of execute it wasn't changed.
The assignment lastFocused = elements[0]; should work, here is a demonstration:
#include <iostream>
#include <string>
#include <vector>
typedef std::string CanvasElement;
void execute(std::vector<CanvasElement*>& elements, CanvasElement*& lastFocused)
{
lastFocused = elements[0];
}
int main()
{
std::string a = "hello";
std::string b = "world";
std::vector<std::string*> vec;
vec.push_back(&a);
vec.push_back(&b);
std::string* p = 0;
execute(vec, p);
if (p == &a)
{
std::cout << "It worked :-)\n";
}
else
{
std::cout << "It did not work :-(\n";
}
}
By the way, there are people who would argue that the following signature would be better:
CanvasElement* lastFocusedCanvasElement(std::vector<CanvasElement*>& elements)
That is, you should return a pointer value instead of changing a pointer variable.
I was able to solve this problem by storing a reference to the pointer in a vector and updating that stored reference. I do not know why setting it directly did not work, but this hack got the job done.