Can somebody please explain the segfault here:
class foo
{
private:
some_class *test_;
void init_some_class(some_class*);
void use_class();
}
foo::foo()
{
//test_ = new some_class(variables, variables); //THIS WOULD WORK
}
void foo::init_some_class(some_class *tmp)
{
tmp = new some_class(variables,variables);
}
void foo::use_class()
{
test_->class_function() //THIS SEGfaults
}
I would call the funtion via init_some_class(test_); If I use new in the constructor then the test_->class_function() works fine. It only seems to segfault when I use new outside of the class constructor and try and pass the pointer through the function
When you write in init_some class() :
tmp = new some_class(variables,variables);
you are in fact storing the new pointer in the parameter that is passed by value. But this parameter is local to the function and lost as soon as the function returns.
So if you call somewhere init_some class(test_) the value of test_ is transferred to tmp, but the changed tmp remains local to the function. You therefore get a segfault beause test_ remains uninitialized.
Possible solutions:
A simple solution to the described use case could be to pass the parameter by reference:
void foo::init_some_class(some_class *& tmp) // note the &
{
tmp = new some_class(variables,variables);
}
With this definition, when calling init_some class(test_), the original test_ pointer gets modified.
Another solution could be to have the init_some_class() change directly the test_ member. You'd then no longer need a parameter.
Related
I'm refactoring this bit of code:
struct GameState {
PieceState piece;
}
//create local copy from piece, modify it, and only when its VALID copy it back!
void update_game_play(GameState *game, const InputState *input) {
PieceState piece = game->piece;
//'left' from perspective of the game
if (input->dleft > 0) {
--piece.offset_col;
}
if (is_piece_valid(&piece, game->board, WIDTH, HEIGHT)) {
game->piece = piece;
}
}
This code takes a piece struct, and only when it's valid it's re-assigned to the GameState struct.
But in my refactored code the assignment gives me a warning that the value is never used in the last line, inside the if-statement:
//create local copy from piece, modify it, and only when its VALID copy it back!
void update(Piece *pieceTmp, Board *board) override
{
auto piece = *pieceTmp;
//'left' from perspective of the game
if (input.dleft > 0) {
--piece.offset_col;
}
//test with dummy if statement
if (true) {
pieceTmp = &piece; //"the value is never used"
}
}
The way I understood it, is that I'm dereferencing the pointer to a object, changing the object properties, and then assign the address of the object to my original pointer? What's going on?
The function accepts the first argument by value.
void update(Piece *pieceTmp, Board *board) override
That is it deals with a copy of the value of the original argument.
So the new value of the pointer
pieceTmp = &piece;
is used nowhere in the function (and in the caller).
Another problem is that you are trying to assign the address of a local variable that will not be alive after exiting the function. So after exiting the function the pointer (if it will be passed by reference) will have an invalid value.
Instead of this statement
pieceTmp = &piece;
you could write for example
*pieceTmp = piece;
I’m working on a beginner(!) exercise.
I am comfortable passing basic variables and also using &variable parameters so I can make changes to the variable that are not destroyed when returning. But am still learning pointers. I am working on the basic Mutant Bunny exercise (linked list practice).
In it I create a linked list by declaring Class Bunny. I set it up as you expect with a data section and a ‘next’ pointer for set up the linkage.
struct Bunny {
string name;
int age;
// more variables here
Bunny* next;
};
Everything works great when I call function to do things like create Bunnies using the function:
Bunny* add_node ( Bunny* in_root ){}
This sets up the node and returns it just like I want. I can also do things like call a function to modify the Bunny class like aging the bunnies.
void advanceAge ( Bunny* in_root ){}
I pass in the head and then I can modify the bunnies in the called function and it stays modified even when it goes back to main. For example I can use:
in_root->age ++;
in the called function and when I return to ‘main’ it is still changed. Basically I can use -> in any called function and it makes the change permanently. I think because the pointer is dereferenced(?) by the -> but still getting my head around it...
So far so good.
The problem comes up when I want call a function to delete the list. (Nuclear option… no more bunnies)
I can delete all the nodes in the called function… but it does not change the Bunny in ‘main’. For example… this does not permanently remove the node.
void DeathCheck(Bunny* in_root){
Bunny* prev_ptr;
prev_ptr = in_root;
if (prev_ptr == NULL){
cout << "No list to check age." << endl; return;
} else {
prev_ptr = NULL; // <- what could I code to have this stick? return;}
// rest of DeathCheck
I’m curious if there is a way to set the node to NULL in the called function and have it stick?
Since you're passing in_root by value, there's no way for it to modify the caller's variable. You could pass it by reference.
void DeathCheck(Bunny* &in_root) {
Bunny *prev_ptr = in_root;
...
in_root = nullptr;
return;
}
Currently, in DeathCheck(Bunny* in_root), there is no way that in_root can be changed, only the object it is pointing to can be changed. (See pass by reference and value with pointers). Based on this, you need to change the parameter to pass-by reference, eg by changing the signature of your function to this:
DeathCheck(Bunny* &in_root)
{
//...
}
This passes the Bunny by reference, meaning that it can now be reassigned to without a copy.
im using my own linked list made with stuct. The struct has 2 ints and 1 pointer to another struct, next.
I'm using the LL (linked list) but in one of the functions a certain pointer won't change.
AddChain( &MakeChain(..values..), added )
this is how i call the function, i send her a new chain to link to the big one, and if there is no big one aka it's NULL so it will replace it. In this call added is a NULL ptr to a chain struct.
void AddChain(PolyChain* pol, PolyChain* main) // adds the new piece to the chain
{
PolyChain *current = main, *back = NULL;
if (main == NULL)
{
pol->next = NULL;
main = pol;
return;
}
... \\ there is continuation of the function but it wont get so far without main one
}
Now, as you can see if the main chain is a NULL I make to to reference to the same thing as the new chain I got. I'm running in the debugger and pol HAS a value and after the line:
main = pol;
main realy changes to point to what pol is pointing to. BUT after the return in AddChain, added which is the main in AddChain is still a NULL. It didn't get the value back from the function, it didn't change the pointer of added as like it was by value and not by reference, but it was by reference.
What's causing this problem?
EDIT: MakeChain returns a PolyChain and AddChain gets PolyChain*, this is why i used &.
This happens because you pass your pointer PolyChain* main by value. A simple way of visualizing "passing by value" is to think about it as "passing by copy": a copy of the pointer is made specifically for the call of AddChain. That is why any change to the pointer inside AddChain remains local to AddChain.
You could fix this problem in three different ways:
Take PolyChain*& main by reference - this is the simplest solution. because nothing else needs to change.
Take PolyChain** main by pointer - in this case AddChain needs to dererefence main, i.e. use *main instead of main, and take a pointer when passing main to AddChain
Return PolyChain* with the new value of main - in this case the caller must make an assignment of the result back to the pointer passed for main.
void AddChain(PolyChain* pol, PolyChain* main)
...
main = pol;
return;
In that code, main is a local copy of whatever pointer was passed in, so assigning to main has no effect on the pointer outside the function.
You didn't give enough information for me to deduce your intent, so it is likely (but not clear) that you could fix the problem by passing the pointer by reference:
void AddChain(PolyChain* pol, PolyChain*& main)
You are changing a copy of the pointer, since you are passing the pointer by value. If you want to change the pointer that comes from the calling scope you will have to pass a pointer to the pointer or a reference to the pointer:
void AddChain(PolyChain*& pol, PolyChain*& main) {...}
You must use pointer to pointer to modify pointer value inside the function
void AddChain(PolyChain* pol, PolyChain** main)
than in your code:
void AddChain(PolyChain* pol, PolyChain** main) // adds the new piece to the chain
{
PolyChain *current = *main, *back = NULL;
if (main == NULL)
{
pol->next = NULL;
*main = pol;
return;
}
... \\ there is continuation of the function but it wont get so far without main one
}
to pass value to the function just call
AddChain(pol, &main);
where pol and main are regular pointers to PolyChain type.
or with simple values:
PolyChain* pMain = &main;
AddChain(&pol, &pMain);
NOTE: This practics are extremaly error prone so you must be extra careful for managing pointers at this manner.
I have created an object of a certain class. The class is "Node" and it has an attribute of CString strName. The value of this variable can be retrieved with a method of Node: CString Node::GetName(), which just returns the name of the variable.
In the following method I instantiate this:
Node* UpperClass::GetObject(CString value) {
Node retObject;
retObject.strName = value;
Trace(retObject.strName); // Prints argument to trace file - this prints the value of strName fine
return &retObject;
}
Then I run this method in a second class:
Node* LowerClass::Get() {
Node *pReturn = instanceOfUpperClass.GetObject();
Trace(pReturn->GetName()); // This trace just prints blank...
return *(&pReturn);
}
As you can see by the code comments, it seems to lose the value when it is passed to the second method. I've attempted to research this but am having some real trouble getting to grips with why.. can anyone help?
As an aside, if one is wondering about the return value of the second method, I am intending to past the resultant pointer to a third function where I utilise it for processing (messy, I know, but I inherited the code and have no choice); just in case that has any bearing on the answer.
Thanks in advance!
int this method:
Node* UpperClass::GetObject(CString value) {
Node retObject;
retObject.strName = value;
Trace(retObject.strName); // Prints argument to trace file - this prints the value of strName fine
return &retObject; // <-- Undefined Baaviour
}
you are returning pointer to local object, which is destroyed once this method ends. You should create retObject dynamically, and return pointer to it, or better put this pointer into shared_ptr<>.
The Node retObject is a local variable when you go out of scope of the function GetObject any use of the object is undefined. And in this case you return a pointer to that object.
I've been banging my head hard over this...I create a pointer in main(), which I pass on to another function. Inside that function, the pointer is used to create a new array (using the new operator), the array is filled, and the function ends.
If I then try to access elements in the new array in the caller, I get a segfault. Since the new operator was used, I expect the new array to be on the heap and thus not cleared by it going out of scope...I really don't get this. What am I overlooking? I also don't know precisely what to google for, so no luck there yet.
I can get it to work if I let the function return the pointer (instead of passing it), but I don't want to do that because eventually I'd like my function to create a few such newly created arrays. So what am I missing here?
Here is a minimal working example:
#include <iostream>
#include <stdio.h>
bool getData(double *myData)
{
myData = new double[2];
if (!myData)
return false;
myData[0] = +4.53;
myData[1] = -3.25;
return true;
}
int main()
{
double *myData = NULL;
if (!getData(myData))
fprintf(stderr, "Could not get data.\n");
std::cout << myData[0] << std::endl;
std::cout << myData[1] << std::endl;
delete [] myData;
}
Root Cause of the Crash:
When you pass a pointer to the function by value. An copy of the pointer gets passed to the function. Further You allocate memory to the copy of pointer passed through main, this pointer is not same as the one you access in main, it is an copy. The pointer myData in main was never allocated any memory, so eventually you are dereferencing a NULL pointer which results in a Undefined Behavior and an crash.
Suggested Solution 1:
Pass the pointer by Reference:
bool getData(double *&myData)
^
And you are good to go.This is the C++ way of doing it.
Another Solution:
You could also do:
bool getData(double **myData)
^
{
*myData = new double[2];
//so on
}
while calling it as:
getData(&myData);
^
A word of caution:
new does not return NULL in case of failure to allocate memory. It throws a std::bad_alloc exception. So you need to handle that exception or in case you want to check for null you should use the nothrow version of new.
The pointer argument to getData() is passed by value, not by reference. This means you're pushing the value (== the address the pointer points to) on the stack and call getData. Inside getData you overwrite this value with the return value from new[]. This value is no longer valid after returning from the function as it only existed on the stack.
Try to pass a reference or pointer to the pointer:
bool getData(double *&myData)
{
myData = new double[2];
if (!myData)
return false;
myData[0] = +4.53;
myData[1] = -3.25;
return true;
}
You have to pass a double** as myData, to initialize correctly your array. Currently, your getData function creates an array and stores its value in the copied parameter, so myData in main is not modified. Your must pass the pointer of myData and modify it with
bool getData(double** myData)
{
*pmyData = new double[2];
...
}
and call getData in main:
getData(&myData);
The myData given as parameter to getData function is passed on stack as a copy. When modifying that value in getData function you actually modify the value from the stack.
When you return to the main function everything is as it was before (except a memory leak).
The quickest solution would be to change the getData function like this:
bool getData(double *&myData)
and you're all set.
You pass the pointer into your function by value, not reference. Try this:
bool getData(double* &myData)
{
...
}
The difference is that myData is now a reference to the pointer in main, not a copy of it that gets destroyed when the function exits.