Given the following code:
[example.h]
class MyClass
{
public:
MyClass();
std::string name;
std::string address;
bool method (MyClass &object);
};
[example.cpp]
MyClass::MyClass()
{
}
bool MyClass::method (MyClass &object) {
try {
object.name = "New Name";
std::cout << "Name: " << object.name << " " << object.address << std::endl;
return true;
}
catch (...) {
return false;
}
}
[test.cpp]
#include "example.h"
int main()
{
MyClass myC;
myC.address = "address";
bool quest = myC.method(myC);
}
What is the difference between the way I've called myC.method in main above, and this alternative way of doing so:
MyClass *myC = new MyClass();
bool quest = myC.method(*myC);
Which is better and why?
In both cases you can send the same value but simply stick with current code is better since it's without pointer dereference and new. You need to take care of delete'ing the object once you are finished with it, which I don't think you need here.
And it's better to use MyClass &object const in the method function so that the reference passed in doesn't get changed.
Using new (and dynamic memory allocation in general) is better if you need the object to last longer that the scope of the function it's being called in. If it's just for a known duration the MyClass myC; local scope version is best (because it's simpler to read and maintain).
When using new your object "myC" won't be deleted until you call delete.
However if you just define it as a local object it will get deleted when it goes out of scope:
{
MyClass myC;
myC.DoSomeStuff();
} // It'll be destroyed here
Related
I very recently started getting into C++, my main language has always been Java.
I want to be able to pass a reference to an object in a constructor so the object constructed can use the passed object and make changes to it.
Doing some research on the subject I've come across copy constructors but I haven't quite understood if they are strictly needed for this operation and what they really accomplish in the first place.
TLDR: I want to learn how to do the equivalent of the following Java code in C++.
Java code
class Master {
private Slave slave;
Master(Slave slave) {
this.slave = slave;
}
public void doSomethingToSlave() {
slave.doSomething();
}
public void changeSlave(Slave s) {
this.slave = s;
}
}
C++ Code ??? -my attempt so far-
class Master {
public:
Master(Slave& slave);
void doSomethingToSlave();
void changeSlave(Slave& s);
private:
Slave& slave; // Is this correct? Do I need to specify that it's a reference?
}
Master::Master(Slave& slave) { // Copy constructor needed?
this->slave = slave;
}
Master::doSomethingToSlave() {
slave.doSomething();
}
Master::changeSlave(Slave& s) {
slave = s;
}
Using Pointers ?
class Master {
public:
Master(Slave* slave);
void doSomethingToSlave();
void changeSlave(Slave* s);
private:
Slave* slave;
}
Master::Master(Slave* slave) {
this->slave = slave;
}
Master::doSomethingToSlave() {
slave.doSomething(); // How do I access the object at slave*?
}
Master::changeSlave(Slave* s) {
slave = s;
}
Here's an example which I hope elucidates the behavior:
#include <iostream>
using namespace std;
class MyType {
public:
int value;
};
int main() {
// value == 1
MyType obj1{1};
// initialize a reference to refer to obj1.
MyType &ref = obj1;
// value == 2
MyType obj2{2};
// ref refers to obj1.
cout << "A. ref.value = " << ref.value << endl;
// this actually reassigns the memory in obj1
// to the memory from obj2.
ref = obj2;
cout << "B. obj1.value = " << obj1.value << endl;
// value == 3
MyType obj3{3};
// initialize a pointer to point to obj3.
MyType *ptr = &obj3;
// ptr refers to obj3.
cout << "C. ptr->value = " << ptr->value << endl;
// now we're just reassigning the pointer value.
// this is like Java reference assignment.
// ptr now points to obj2.
ptr = &obj2;
cout << "D. obj3.value = " << obj3.value << endl;
// now we're reassigning the memory at obj2 to
// the memory from obj1.
// this is what the C++ reference assignment is doing.
*ptr = obj2;
cout << "E. obj2.value = " << obj2.value << endl;
return 0;
}
The output is as follows:
A. ref.value = 1
B. obj1.value = 2
C. ptr->value = 3
D. obj3.value = 3
E. obj2.value = 2
A Java reference is actually like a C++ pointer, but Java doesn't let you do the dereference and assignment *ptr = value.
However, I agree with what others are saying that approaching C++ with the coding style of Java isn't really a good idea. Modern C++ programs don't really use raw pointers. They use smart pointers or value objects, because C++ doesn't have garbage collection. If you're passing raw pointers around, it's difficult to figure out exactly when a particular object needs to be destroyed.
In your case, I think you'd use a std::shared_ptr<Slave>.
A value object is like Slave slave;, which is a stack-allocated object if it's declared in a method body, or it's stored directly inside the memory for an object if it's declared as a member of a class or struct.
A copy constructor (ctor) is used to copy an object, i.e. to create a copy of the object of the same type, given as argument.
In your case,
Master::Master(Slave& slave)
is not a copy ctor, and a copy ctor is not required for Master.
However, Slave should have a copy ctor and an assignment operator due to
Master::changeSlave(Slave& s) {
slave = s;
}
This is because you are assigning a copy of s to the object that slave points to. This is likely not what you wanted to do. To reassign the pointer, do use a pointer (rather smart than raw ointer) and not a reference, which cannot be reassigned.
Helpful references:
For me, C++ for Java Programmers, especially the summary of differences between C++ and Java, has helped moving from Java to C++.
About cloning: Though assignment operators and regular ctors are usually used, the clone pattern is also helpful in C++. Good examples can be found in Item 25 of More Effective C++ (Virtualizing ctors and non-member functions).
I was about to ask a rather simple beginner question the other day about a c++ function I was working on when I realized I hadn't released the memory for my function. That never seems to end well around here.
It seems like this would be a common question but I wasn't able to find anything at my level of understanding in c++
How would I properly free memory in this code
#include <iostream>
class thing{
public:
int a;
};
thing makeThing(){
thing *t = new thing;
t -> a = 5;
return *t;
}
int main(){
thing thing1 = makeThing();
std::cout << "a: " << thing1.a << std::endl;
return 0;
}
As far as I know I'm not able to free it after the function terminates.
I tried this:
delete &thing1;
but based on the core dump, I assume that’s not the way to do it.
Since you return by value, that means you return a copy of the object. The original object, created by new things, can't be reached after the function returns (not reliably anyway).
You can return a pointer:
thing* makeThing(){
thing *t = new thing;
t -> a = 5;
return t;
}
And delete that.
But you should really just return an object, and not even allocate anything with new in this case.
Sometimes the simplest way to free memory is to not have allocated it to begin with:
thing makeThing(){
thing t;
t.a = 5;
return t;
}
The reason what you're trying to do doesn't work is that when you have:
delete &thing1;
that's the address of your local object... that's not the address of what you actually allocated. That one got copied into yours, and now you have no way to access it.
If you wanted to allocate your thing, you would need to return the pointer directly. Preferably, wrapped somehow:
std::unique_ptr<thing> makeThing() {
std::unique_ptr<thing> t(new thing);
t->a = 5;
return t;
}
thing makeThing(){
thing *t = new thing;
t -> a = 5;
return *t;
}
Leads to an immediate memory leak. The t variable will go out of scope after makeThing() returns, and the allocated memory will never be released or accessible for release with an appropriate delete statement.
There's a copy of the newly created t returned.
To fix it just create a local variable and retun a copy:
thing makeThing(){
thing t;
t.a = 5;
return t;
}
If you really want to use new this is the right way to do it. This code is C++11, so you may need to turn on some option if that is not already the default in the compiler you are using. I habitually use C++11, since the improvements in that version of the language are really worthwhile.
#include <iostream>
#include <memory>
#include <ostream>
class thing {
public:
int a;
};
std::ostream& operator<<(std::ostream& os, const thing& t) {
os << t.a;
return os;
}
std::unique_ptr<thing> makeThing() {
std::unique_ptr<thing> t(new thing);
t->a = 5;
return std::move(t);
}
int main() {
auto thing1 = makeThing();
std::cout << "a: " << *thing1 << std::endl;
return 0;
}
But really if all you want to do is create an object there is no need to allocate it on the heap. You can just do it like the code below. Notice that the object is created without the use of new. The object is copied when it is returned from makeThing(), and the compiler uses the default copy constructor for class thing (which I did not replace) when doing that.
#include <iostream>
#include <ostream>
thing makeThing() {
thing t;
t.a = 5;
return t;
}
int main() {
auto thing1 = makeThing();
std::cout << "a: " << thing1 << std::endl;
return 0;
}
The ostream inserter does not need to change, so I omitted it. Same for the class definition.
Why is it that I can access the data held within the object after assigning the pointer WHILE I'm within the scope of the assigning function, but cannot once I try to access the same value through the same pointer but outside of that function?
The pointer is a member function and is assigned within the function. Within the function, that works fine. But, when from within that function, I call ANOTHER function which uses the class scope, the pointer misbehaves, presenting garbage data. Why?
CODE:
#include <iostream>
class Object{
public:
Object( ) { std::cout << "Object constructor called." << std::endl; }
Object( const Object &in ) { i = in.i; std::cout << "Object copy constructor called." << std::endl; }
~Object( ) { std::cout << "Object destructor called." << std::endl; }
int i;
};
class ObjectManager{
public:
Object * retObject(){
Object *myObject = new Object;
myObject->i=55;
return myObject;
}
};
class LogicManager{
public:
LogicManager(){
myObjectManager = new ObjectManager;
}
~LogicManager(){
delete myObjectManager;
}
Object * retObject(){
return myObjectManager->retObject();
}
private:
ObjectManager *myObjectManager;
};
class Viewer{
public:
~Viewer( ) { if( myObject ) { delete myObject; } }
void ptrinObject( LogicManager * inLogic ){
myObject = inLogic->retObject();
std::cout << "Got path size of " << myObject->i << std::endl; //correct
std::cout << "Got path size of " << retObjectVal( ) << std::endl; //0?!?!?!?
}
int retObjectVal( ) { myObject->i; }
private:
Object *myObject;
};
int main(){
LogicManager myManager;
Viewer myViewer;
//myViewer.cpyinObject( &myManager );
myViewer.ptrinObject( &myManager );
return 0;
}
OUTPUT:
Object constructor called.
Got path size of 55
Got path size of 861280848
Object destructor called.
The problem is:
int retObjectVal( ) { myObject->i; }
There is no return statement in that function. You just have an expression with no side effect. As a result, we run into §6.6.3/2:
Flowing off the end of a function is equivalent to a return with no value; this results in undefined
behavior in a value-returning function.
It's undefined behavior what it returns, so it ends up returning some garbage. Just make it:
int retObjectVal() { return myObject->i; }
This is an easy mistake to make, which is why you should always try to compile with the highest warning settings possible. For instance, on gcc with no flags, I get no warnings. But with -Wall, I get:
warning: statement has no effect [-Wunused-value]
warning: no return statement in function returning non-void [-Wreturn-type]
First, you're not initializing Viewer::myObject so if you just do
void something() {
Viewer v;
}
You may end up trying to delete an invalid pointer.
myViewer.cpyinObject( &myManager );
myViewer.ptrinObject( &myManager );
Both functions create a new Object but neither checks to see if there's already one allocated (memory leak). Then later, they immediately ignore that new object created and instead assign yet another new Object allocated by ObjectManager (more memory leaks).
Finally, Viewer::retObjectVal does not actually specifically return a value and therefore you are receiving "junk off the end of the function".
I suggest you look at your compiler warnings as any sensible compiler will have warned you about the first and third issues I've mentioned.
In the Viewer class, you are missing a return statement:
int retObjectVal( ) { return myObject->i; }
should work.
What you have is a method where some of its branches fall off without returning a value. This leads to undefined behavior. You are simply evaluating "myObject->i;" as a statement.
Another issue you should probably address is that your Object pointers are not owned by anyone and not being deleted anywhere. Namely, you are deleting your ObjectManager but nowhere does it delete the underlying object itself. You should probably figure out an ownership model there, have someone keep track of these pointers, and delete them when appropriate.
I'm trying to make a kind of screen manager in C++ but I'm getting errors.
With my code below I receive
1>screenmanager.cpp(26): error C2664: 'void std::vector<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'virtualGameScreen' to 'virtualGameScreen *&&'
1> with
1> [
1> _Ty=virtualGameScreen *
1> ]
1> Reason: cannot convert from 'virtualGameScreen' to 'virtualGameScreen *'
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>
Errors occur with gameScreen.push_back(gameScreenToAdd);
I get access violation error when adding a reference operator with gameScreenToAdd.
ScreenManager.h
void AddScreen(virtualGameScreen);
void RemoveScreen(virtualGameScreen);
ScreenManager.cpp
std::vector<virtualGameScreen*> gameScreen;
void ScreenManager::Initialize(void)
{
MainMenu menu = MainMenu();
AddScreen(menu);
}
void ScreenManager::AddScreen(virtualGameScreen gameScreenToAdd)
{
gameScreenToAdd.LoadContent();
gameScreen.push_back(gameScreenToAdd);
}
So, I've hit a bit of a wall, any suggestions on how I might fix this?
edit game runs if I change gameScreen.push_back to gameScreen.push_back(new MainMenu()); buut that's not really how I want the function to work
So, the first thing the compiler did is tell you where the problem occurs:
1>screenmanager.cpp(26)
It also told you primarily what the problem is:
Reason: cannot convert from 'virtualGameScreen' to 'virtualGameScreen *'
So - something in your code is providing a "virtualGameScreen" object instance where it was expecting a pointer (denoted by the *). And it's on line 26. The other parts of the error indicate it's the call to push_back. Lets look at line 26:
gameScreen.push_back(gameScreenToAdd);
Yep - you're calling push_back, and you're passing it gameScreenToAdd, which is of type virtualGameScreen. The push_back call is from this vector:
std::vector<virtualGameScreen*> gameScreen;
Your vector expects pointers, so the push_back expects vectors.
HOWEVER: You can't just do this:
gameScreen.push_back(&gameScreenToAdd);
because gameScreenToAdd is a temporary function variable - when you call AddScreen, the original variable is copied into a new, temporary virtualGameScreen for the lifetime of the function call. That means when the program leaves AddScreen the screen whose address you pushed will no-longer exist (the memory is still there, but it has been released and the computer will now proceed to use it for other reasons).
What you'll need to do is change AddScreen to take a pointer.
void ScreenManager::AddScreen(virtualGameScreen* gameScreenToAdd)
{
gameScreenToAdd.LoadContent();
gameScreen.push_back(gameScreenToAdd);
}
Unfortunately, this leaves you open to yet another problem with your code.
void ScreenManager::Initialize(void)
{
MainMenu menu = MainMenu();
AddScreen(menu);
}
This function creates a temporary, local MainMenu object - with a lifetime of the duration of Initialize. Then it creates a second, temporary MainMenu and copies it to menu.
If you write
AddScreen(&menu);
it will work, but it will pass the address of a temporary instance to AddScreen.
As soon as program flow leaves the "Initialize()" function, your value goes away.
It looks like you may have some prior experience with something like Java or C# and are trying to apply previous knowledge to C++.
What you need is a member variable to store "Menu" for the life time of the instance of ScreenManager.
Option 1: Just use a class member variable.
class ScreenManager
{
MainMenu m_menu;
public:
ScreenManager()
: m_menu() // initialize menu while we are initializing.
{}
void Initialize()
{
AddScreen(&m_menu);
}
// ...
};
If you really want to use a pointer, you might do the following:
class ScreenManager
{
MainMenu* m_menu;
public:
ScreenManager()
: m_menu(nullptr) // make sure it's null as soon as the object is created
{}
void Initialize()
{
m_menu = new MainMenu();
AddScreen(m_menu);
}
// but now we have to make sure it is released when we go away
~ScreenManager()
{
if (m_menu)
{
delete m_menu;
m_menu = nullptr;
}
}
};
Option 3: use C++ containers to manage the lifetime of the pointer for you, either std::unique_ptr or std::shared_ptr
---- EDIT ----
Seeing the edit you made while I was writing this, it's a little clearer what you're trying to do. What you probably want is something more like this:
std::vector<std::unique_ptr<virtualGameScreen>> gameScreen;
Consider the following:
Live demo: http://ideone.com/7Th2Uk
#include <iostream>
#include <vector>
class Foo {
const char* m_name;
public:
Foo(const char* name) : m_name(name) { std::cout << "Foo " << m_name << '\n'; }
~Foo() { std::cout << "~Foo " << m_name << '\n'; }
};
int main() {
std::vector<Foo*> foos;
Foo foo("foo");
foos.push_back(new Foo("new"));
return 0;
}
Note that the second foo is never released.
Foo foo
Foo new
~Foo foo
std::unique_ptr is a pointer-container object which will delete the object when the object expires. This makes it suitable for use in a container like std::vector
#include <iostream>
#include <vector>
#include <memory> // for std::unique_ptr
class Foo {
const char* m_name;
public:
Foo(const char* name) : m_name(name) { std::cout << "Foo " << m_name << '\n'; }
~Foo() { std::cout << "~Foo " << m_name << '\n'; }
};
int main() {
std::vector<std::unique_ptr<Foo>> foos;
Foo foo("foo");
foos.emplace_back(new Foo("new"));
return 0;
}
Both objects get cleaned up:
Foo foo
Foo new
~Foo foo
~Foo new
Now you don't need your m_menu at all, you can simply call AddScreen with a 'new MainMenu()' and the pointer will be added to the vector such that when the vector goes out of scope, proper cleanup will happen.
Menu* menu = new MainMenu();
AddScreen(menu);
or
AddScreen(new MainMenu());
In theory what you should really do is ensure that the allocation goes straight into a unique_ptr object so that there's no window for it to get leaked, but teaching the use of std::unique_ptr is beyond the scope of this answer. http://msdn.microsoft.com/en-us/library/hh279676.aspx, http://www.drdobbs.com/cpp/c11-uniqueptr/240002708, etc.
In pre-C++11 code, you might have something like this:
std::vector<virtualGameScreen*> gameScreen;
void ScreenManager::Initialize(void)
{
AddScreen(new MainMenu);
}
void ScreenManager::AddScreen(virtualGameScreen *gameScreenToAdd)
{
gameScreenToAdd->LoadContent();
gameScreen.push_back(gameScreenToAdd);
}
but you would have to have some way to make sure the object got deleted.
With C++11, you would probably want to have the memory managed automatically:
std::vector<std::unique_ptr<virtualGameScreen>> gameScreen;
void ScreenManager::Initialize(void)
{
AddScreen(std::unique_ptr<MainMenu>(new MainMenu));
}
void ScreenManager::AddScreen(std::unique_ptr<virtualGameScreen> gameScreenToAdd)
{
gameScreenToAdd->LoadContent();
gameScreen.emplace_back(std::move(gameScreenToAdd));
}
That's because you did not provide a pointer to the vector (gameScreen), and another issue about the code is that: the paramater will generate a temp object, if just put the address of it the app maybe crash.
i am having trouble with my code. I am abit stumped.
I have a data member which is a pointer to a string type.
I use the constructor as a defualt initialer to this pointer, then when I call an object in the main function the intialised pointer to points to the memory address where the string is stored and prints the contents. That is what is supposed to happen, but I can't get the program to work. May somebody please tell me where I am going wrong?
#include<iostream>
#include<string>
using namespace std;
class NoName{
public:
NoName(string &sName("Alice In Wonderland") ){};
private:
string *pstring;
};
int main(){
//the constructor will be automatically called here once a object is created
// and the string "Alice in Wonderland" will appear on the screen
return 0;
}
Just simply use a std::string member and initialize it in Member initializer list:
private:
string mstring;
public:
NoName():mstring("Alice In Wonderland"){}
You could also let the constructor take in a parameter instead of hardcoding the string and let the user pass the string at run-time:
NoName(std::string str):mstring(str){}
You do not need a pointer. By using a pointer to std::string You nullify the advantages of implicit manual memory management offered by std::string.
If you really need to store a pointer for some reason, then there are some points to remember:
Pointers are initialized like new Class
Prefer to initialize class members in the member initializer list
Any time you write the word new think about where you're going to write delete. (In this case it goes in the destructor.
Rule of Three: If you need a destructor (you do, because of delete), then you also need a copy constructor and copy assignment operator.
This is one way your code could look: http://ideone.com/21yGgC
#include<iostream>
#include<string>
using std::cout; using std::endl;
using std::string;
class NoName
{
public:
NoName(string sName = "Alice In Wonderland") :
pstring(new string(sName))
{
cout << "ctor - " << *pstring << endl;
}
NoName(const NoName& rhs) :
pstring(new string(*rhs.pstring))
{
cout << "Copy ctor - " << *pstring << endl;
}
NoName& operator=(const NoName& rhs)
{
*pstring = *rhs.pstring;
cout << "Copy assignment operator - " << *pstring << endl;
return *this;
}
~NoName()
{
cout << "dtor, my name was " << *pstring << endl;
delete pstring;
}
private:
string *pstring;
};
.
int main()
{
NoName m, n("Another name");
NoName o(m);
o = n;
return 0;
}
Notice how much easier it is if you don't use the unnecessary pointer:
class Better
{
public:
Better(string sName = "Alice In Wonderland") :
m_string(sName)
{
}
private:
string m_string;
};
Because you don't need the custom destructor, you also don't need the copy constructor or copy assigment operator either. Much easier!
You're not using the constructor properly. First of all, you create this reference parameter and try to initialize it to a string object (that's asking for problems). Second, your constructor never actually does anything.
You need to call new on your pointer, dereference it and give the data pointed to a value, output the dereferenced value with std::cout and then clean the memory up with delete in the destructor (or in this case, you can do it after you use cout if you're not planning on using that string again. But do it in the destructor if you need it still).
Assuming you're doing this for a class, your textbook should tell you how to do these things.
EDIT: this is also not the default-constructor. I changed your tag to match appropriately.