Summarizing:
Is it possible to change a class member property memory address?
What lead me to do this question:
I'm not sure if what I want to do will lead into my expected behavior, and even if it works as expected, if it is what I should do.
So, I have a member property which I want to read from disk, say for instance that it is prop from MyClass. The routine I have that read the property from disk getVarOnFile I do not have access to the implementation, but it uses a pointer to the type to fill the value on the file.
In the documentation it says that if the property does not exists, the pointer may be null, although I am unsure if it will set it to null or it is because it expects that I enter null pointer to the function.
Because of that, instead of using the destVar pointer itself, I use a localVar pointer, and then set the destVar to localVar.
But I am not sure if I should do that, it seems that this will segment memory, where most of the members are close in the memory, but not this one that I set to the memory place reserved by the file.
void readHelper(const char* propOnFile, float*& destVar)
{
// check if propOnFile exists
float *localVar = nullptr;
getFileOnVar(propOnFile,localVar);
if ( localVar != nullptr){
destVar
}
}
class MyClass {
private:
float prop;
public:
static MyClass *read(const char* file){
readHelper("prop",&(this->prop));
}
};
I am not sure what would happen to the original memory place reserved for the original class property member, which was replaced to a new place. It will be freed or this would be memory leak?
Changing class member address
If I understand your question correctly, that is not possible.
Say you have:
struct Foo
{
int a;
};
Foo f;
Once you have created f, the address of f and f.a are not changeable. You can only modify their values.
Related
I read that it is good practice to do a check in the destructors of classes after deletion for pointer data members as follows:
if( 0 != m_pPointer)
{
delete m_pPointer;
m_pPointer= 0;
}
However, I found out that this prevents you to declare const pointers as data members as follows:
Type* const m_pPointer;
Isn't assigning NULL to pointers(as in my example above) a barrier for const-correctness?
What is the best way to do? Keep everything const and stop assigning NULL to the deleted pointer or declaring non-const pointers even though their address never changes?
This is bad practice for the following reasons:
Setting a pointer to null in the destructor may mask double destruction problem. Good practise is to detect problems as early as possible.
Checking a pointer for null before deleteing it only adds unnecessary code. delete handles null pointers by doing nothing. Good practice is to minimize the amount of code.
Deleting a null pointer is guaranteed safe, so that null check is pointless.
If a class has a member that is a const pointer to a non-const object then you're saying the pointer value WILL NOT change within the lifetime of the wrapping object - that being the case you should only do this in the case where the object pointed to will live as long or longer than the wrapping object and the wrapping object will never want to point to a different object.
The fact that you have this issue simply means you've used a const pointer in the wrong place. You claim that in your case the pointer value never changes, but in your example it obviously does - it changes to null.
The "best way to do" is:
class foo {
std::unique_ptr<bar> m_pPointer;
public:
foo(std::unique_ptr<bar> pPointer)
: m_pPointer{std::move(pPointer)} {}
};
or for const,
class foo {
const std::unique_ptr<bar> m_pPointer;
public:
foo(std::unique_ptr<bar> pPointer)
: m_pPointer{std::move(pPointer)} {}
};
No new, no delete, no destructor.
A weird situation can be caused when you link a static lib with a global or static object from two different shared libs (on Linux) which later be linked to the same executable.
Each shared lib object insert call to constructor and destructor, so you'll have one object and two calls for constructor and destructor for the same object (actually you'll have 2 objects mapped to the same address).
You'll probably find the problem when your app crash in the 2nd destructor.
if you NULL it you'll never know that there was a problem at all.
for your question: except for the above issue, I think you should distinct two types of pointers:
See the class below:
class A{
obj *x, *y;
A(){
x = new obj;
y = NULL
}
~A(){
delete x;
if(y)delete y; // the `if` here will save the calling and returning run time when NULL.
}
void RecicleX(){
delete x;
x = new obj;
}
void InitY(){
assert(y==NULL); //illegal to call init when already
y = new obj;
}
void TermY(){
assert(y); //illegal to call term when already inited
delete y;
y = NULL; //prevent crush in dtor if called after...
}
};
x is always exists, so no need to check it, and no need to null it. y may exists and may not, so I think you should null it after deletion.
(You maybe will want also to know the current state, like for assert)
I have a class with a static member that's a pointer like so :
animation.h
class Animation
{
public:
Animation();
static QString *m;
};
animation.cpp
#include "animation.h"
QString* Animation::m = 0;
Animation::Animation()
{
}
When I try to initialize that 'm' pointer from another class like so :
Animation::m = new QString("testing");
It works.
But when I do it this way :
QString x("Testing");
Animation::m = &x;
The program crashes.
What is wrong with this second method ?
Also I would like to have that static pointer as private so I can make static getter and setter functions to it. The setter should use the second method as the 'x' will come in a parameter so I'm stuck.
Thanks for any help!
I bet it's not crashing on that line, but afterwards.
The problem is that you're taking the address of a variable located in automatic memory, and probably try to access it afterwards. The variable x will be destroyed when it's scope ends, but Animation::m will still point to that memory (memory you no longer own after x went out of scope). This results in undefined behavior.
Just like the following would be illegal:
int* x = NULL;
{
int k = 3;
x = &k;
}
*x = 4;
Workaround assign to the value, not the pointer (provided it was previously assigned to a valid QString*):
QString x("Testing");
*(Animation::m) = x;
What is wrong with this second method ?
It crashes because you most likely access it beyond the scope in which x was created.
Automatic variables are automatically destroyed once the control exits the scope { } in which they were created, So beyond the scope what you have is an pointer pointing to data that does not exist. Accessing this data causes an Undefined Behavior and a crash.
How to go about it?
You should dynamically allocate memory and then copy the string to the dynamically allocated pointer so that you are able to access it everywhere. This way the string remains valid unless and untill explicitly deleteed.
I'll bet that your program crashes when you use Animation::m after x has been destroyed (probably by going out of scope).
If you want to use a setter to assign to Animation::m, you'll need to pass in the argument as a pointer or by reference:
class Animation
{
public:
Animation();
void set_m( QString* ptr) {
m = ptr;
}
void set_m( QString& ref) {
m = &ref;
}
private:
static QString *m;
};
However, you'll still need to make sure that whatever m points still is still alive when you try to use m.
I have a class Message and a class Cache.
In Message::processMessage() fn. I create a instance of another class CacheRef(not shown below.)
then I call Cache::cacheData(cacheRef)
Now, in Cache class, I have a map which has its key as CacheReference. I store the ref that I passed to cacheData fn. in this map.
class Message
{
private:
Key m_key;
public:
void processMessage(int a, int b, Cache *pCache)
{
CacheRef ref(a, b, m_key); //CacheRef is a class defined in same file
//some char *data - do processing an dfill it!!
pCache->cacheData(ref, data);
}
}
class Cache
{
public:
void cacheData(CacheRef &ref, const char* data)
{
CacheDir *dir;
std::map<<CacheRef, CacheDir*>::iterator it = m_dirs.find(ref);
if(it == m_dirs.end())
{
dir = new CacheDir();
m_dirs.insert(ref, dir);
}
}
std::map<CacheRef, CacheDir*> m_dirs; //CacheDir is some class defined in the same file
}
Now, the code is working absolutely fine. But I have this concern(not sure!!) that I am storing some local variable in map, which which cease to exist as soon as processMessage()fn. exits. So, am I accessing some invalid memory, is it just by luck that this code is working.
If this is wrong, what is the best way to achieve this behaviour?
I don't have boost on my system, so can't use shared_ptr for anything.
Because the 1st template parameter is a CacheRef (and not a reference or pointer to a CacheRef) then ref will be copied into the map when you do the insert. Hence, you won't be storing a reference to a local stack variable.
As long as there is an appropriate copy constructor or assignment operator for CacheRef then this will work ok.
As Stephen Doyle pointed out, you are actually storing a copy of the CacheRef in the map, not a reference to the one passed to the cacheData() method.
Whether this causes a problem or not depends on the definition of the CacheRef class. If, for example, a CacheRef holds a pointer or a reference to the Key passed to the constructor, you will end up with an invalid pointer once the Message instance is destroyed.
By the way, since you are storing dynamically allocated objects of CacheDir in Cache::m_dirs, you should make sure to delete all values in the map in the Cache::~Cache() destructor to avoid memory leaks.
I am trying to write a function that will check if an object exists:
bool UnloadingBay::isEmpty() {
bool isEmpty = true;
if(this->unloadingShip != NULL) {
isEmpty = false;
}
return isEmpty;
}
I am pretty new to C++ and not sure if my Java background is confusing something, but the compiler gives an error:
UnloadingBay.cpp:36: error: no match for ‘operator!=’ in ‘((UnloadingBay*)this)->UnloadingBay::unloadingShip != 0’
I can't seem to figure out why it doesn't work.
Here is the declaration for class UnloadingBay:
class UnloadingBay {
private:
Ship unloadingShip;
public:
UnloadingBay();
~UnloadingBay();
void unloadContainer(Container container);
void loadContainer(Container container);
void dockShip(Ship ship);
void undockShip(Ship ship);
bool isEmpty();
};
It sounds like you may need a primer on the concept of a "variable" in C++.
In C++ every variable's lifetime is tied to it's encompassing scope. The simplest example of this is a function's local variables:
void foo() // foo scope begins
{
UnloadingShip anUnloadingShip; // constructed with default constructor
// do stuff without fear!
anUnloadingShip.Unload();
} // // foo scope ends, anything associated with it guaranteed to go away
In the above code "anUnloadingShip" is default constructed when the function foo is entered (ie its scope is entered). No "new" required. When the encompassing scope goes away (in this case when foo exits), your user-defined destructor is automatically called to clean up the UnloadingShip. The associated memory is automatically cleaned up.
When the encompassing scope is a C++ class (that is to say a member variable):
class UnloadingBay
{
int foo;
UnloadingShip unloadingShip;
};
the lifetime is tied to the instances of the class, so when our function creates an "UnloadingBay"
void bar2()
{
UnloadingBay aBay; /*no new required, default constructor called,
which calls UnloadingShip's constructor for
it's member unloadingShip*/
// do stuff!
} /*destructor fires, which in turn trigger's member's destructors*/
the members of aBay are constructed and live as long as "aBay" lives.
This is all figured out at compile time. There is no run-time reference counting preventing destruction. No considerations are made for anything else that might refer to or point to that variable. The compiler analyzes the functions we wrote to determine the scope, and therefore lifetime, of the variables. The compiler sees where a variable's scope ends and anything needed to clean up that variable will get inserted at compile time.
"new", "NULL", (don't forget "delete") in C++ come into play with pointers. Pointers are a type of variable that holds a memory address of some object. Programmers use the value "NULL" to indicate that a pointer doesn't hold an address (ie it doesn't point to anything). If you aren't using pointers, you don't need to think about NULL.
Until you've mastered how variables in C++ go in and out of scope, avoid pointers. It's another topic entirely.
Good luck!
I'm assuming unloadingShip is an object and not a pointer so the value could never be NULL.
ie.
SomeClass unloadingShip
versus
SomeClass *unloadingShip
Well, you don't have to write so much code to check if a pointer is NULL or not. The method could be a lot simpler:
bool UnloadingBay::isEmpty() const {
return unloadingShip == NULL;
}
Plus, it should be marked as "const" because it does not modify the state of the object and can be called on constant instances as well.
In your case, "unloadingShip" is an object of class "UnloadingShip" which is not dynamically allocated (except when the whole class "UnloadingBay" is allocated dynamically). Thus, checking if it equals to NULL doesn't make sense because it is not a pointer.
For checking, if an object exists, you can consider going this way:
create a pointer to your object:
someClass *myObj = NULL // Make it null
and now where you pass this pointer, you can check:
if(!myObj) // if its set null, it wont pass this condition
myObj = new someClass();
and then in case you want to delete, you can do this:
if(myobj)
{
delete myObj;
myObj = NULL;
}
so in this way, you can have a good control on checking whether your object exists, before deleting it or before creating a new one.
Hope this helps!
This problem involved me not knowing enough of C++. I am trying to access a specific value that I had placed in the Heap, but I'm unsure of how to access it. In my problem, I had placed a value in a heap from a data member function in an object, and I am trying to access it in another data member function. Problem is I do not know how, and I had searched examples online, but none were what I needed as they were all in int main() and were not specifically what I needed.
In the first data member function, I declare the value I want to be sent to the Heap;
Here's an example of what my first data member function.
void Grid::HeapValues()
{
//Initializing Variable
value = 2; //The type is already declared
//Pointers point a type towards the Heap
int* pValue = new int;
//Initialize an a value of in the Heap
*pValue = value;
}
And in data member function This is what want:
void Grid::AccessHeap()
{
//Extracting heap:
int heap_value = *pValue; //*pValue does not exist in this function
cout << heap_value; //Delays the value 2, which is found
//in the first data member function
}
I feel foolish for asking, but I am unable to find the answers and do not how. Does anyone know how to access a value from the heap in a simple way? And I would need it to be able to access in more then two data member function.
pValue needs to be a member-variable of the class Grid.
class Grid
{
private: int* pValue;
public: void HeapValues();
void AccessHeap();
};
Now the member-variable pValue is accessible from any member-function of Grid.
Don't forget to delete your pointer in the destructor when you are done. For more information visit:
http://www.cplusplus.com/doc/tutorial/variables.html <-- Variable scope
http://www.cplusplus.com/doc/tutorial/pointers.html <-- Pointers
http://www.cplusplus.com/doc/tutorial/dynamic.html <-- Dynamic memory
Like Aaron said you can make the value a member of your Grid class. In this case though there is no need for it to be a pointer to an int.
class Grid
{
private:
int value;
public:
void HeapValue();
void AccessHeap();
};
The value will be stored as part of the object wherever it is instanciated. You can make it on the stack or the heap, it doesn't matter. For simple values like the built in types and Objects that will be owned by the instance of the class it is unnecessary to allocate them using new. This way you don't need to worry about cleaning up with the delete operator in the Grid destructor, just make sure you dispose of the owning Grid instance properly ;-)
Of coarse there are exceptions to this that you will learn as you delve more into C++, but for your example the above will be fine.
Why do you want it on the heap? If you add it as part of the class then it will be in the same place the class is, possibly on the stack or in global memory. Perhaps you want to have a variable size to your integer pointer? In that case, then you need to be sure to deallocate the memory when you are done with it.
The problem with stuff on the heap is finding it. There is no accessing it by name, unless you add a mechanism for that. Somehow you need to communicate the location to whatever code needs to access it. In this case, it looks like you only need access within the Grid class, so it is easy. Just make it a member variable like Aaron indicates. You might end up with something like:
class Grid
{
protected:
int* pVals;
public:
Grid() pVals(NULL) { }
~Grid() { delete [] pVals; }
void HeapValues() {
pVals = new int[getHeapValuesSize()];
pVals[0] = 1; // ...
}
void AccessHeap() {
cout << pVals[0]; // ...
}
(On a side note, you appear to be using the phrase "data member function" when you mean "member function". "Data member" refers to member data of a class, like pVals, but I'm not sure what "data member function" would mean.)