Node * replaceValue(Node * x) const
{
if (x == nullptr)
return nullptr;
if (x->left != nullptr)
replaceValue(x->left);
else
return x;
}
Warning: control reaches end of nonvoid function
Should i just ignore this? I made sure that this function always returns something (all pointers initialized with nullptr), but I don't want this warning to keep popping up. If I add a return nullptr at the end of the function, then it just crashes. Is there any way around this?
Never ignore a warning. It's telling you something important.
In this case when you call replaceValue recursively, you're throwing away the return value from that call then falling out the bottom of the function without returning anything.
You probably want to use return replaceValue instead.
Although it's a very old question still I will answer it.
It is like not providing a default case to a switch statement. When the control reaches the end of your non-void function it doesn't have anything to return, in case all of your conditions fail. I believe the compiler does this so that you take care of all the corner cases and possibilities for the function. For example, if the user enters a value of a datatype which you haven't used in your function then without throwing an exception a default value can be returned instead.
If you don't want to do this you can always use a void function that doesn't return anything.
You should consider adding a return statement like this so that after the recursive call a value is returned.
if (x->left != nullptr)
return replaceValue(x->left);
But if you are sure that your function takes care of all the corner cases and the control will never reach the default value then you can add return x at the end just like this. The return x here is just to suppress the error message and nothing else in your case.:
Node * replaceValue(Node * x) const
{
if (x == nullptr)
return nullptr;
if (x->left != nullptr)
replaceValue(x->left);
else
return x;
return x; // Default value
}
Related
Suppose we have the following piece of C++ code
const Person *Person::getParent() const {
return m_condition ? m_parent : nullptr;
}
int Person::parentAge() const {
// checking for nullptr
if (getParent() == nullptr) {
return -1;
}
return getParent()->getAge(); // warning: potential null pointer dereference
}
This is an overly simplified version, but I think it drives the point home. The point is, even though in the beginning of parentAge() method I have a guard condition to check whether or not getParent() returns nullptr, when compiling this code with -Wnull-dereference flag, I get the warning if I call the getParent() method even after the check. Why does this happen? Is it because of the way getParent() is written and the compiler doesn't "see" the guard condition, and will throw a warning if it sees that the method can potentially return a nullptr?
For reference, the warning is gone if I save the return value of getParent() into a variable and use it at a later point in time instead of calling the method again:
int Person::parentAge() const {
// checking for nullptr
auto parent = getParent();
if (parent == nullptr) {
return -1;
}
return parent->getAge(); // no warning generated here
}
I am compiling a c++ NodeList class and I am getting the warning "control reaches end of non void function" but I do have return statements in the functions that give the error and I am not clear of what is causing the error.
I have tried putting a return statement inside a for loop, which should work by breaking out of the function once it reaches it, and also trying to use a separate pointer.
DataType * ArrayList::insertAfter(const DataType & target,const DataType & value){ // *This function replaces an array element with a parameter (DataType objects)* //
for(size_t i = 0 ; i < m_size ; i++){
if (m_array[i] == target){
m_array[i+1] = value;
return &m_array[i+1];
}
}
}
I expect the files to compile but the warnings prevents this.
Turning my comment into an answer:
The return might not execute if the if condition is never satisfied or the for loop never runs.
Therefore, you should return some default value after the end of the for loop (maybe nullptr in this case?). Another option is throwing an exception.
we're learning about recursion in school.
From what I've read online, you can optimize recursive functions by making the recursive step to be the last thing the function does.
But is the return keyword needed? Even for void functions?
void insert(Node<T>*& n, T value)
{
if (n == nullptr)
{
n = new Node<T>(value);
return;
}
else if (value < n->get_value())
{
Node<T>* left = n->get_left();
return insert(left, value);
}
else
{
Node<T>* right = n->get_right();
return insert(right, value);
}
}
Would this still be tail recursion without the return keyword?
Specifically in the else if, because without it, it would "no longer be the last thing the functions does".
Specifically in the else if, because without it, it would "no longer be the last thing the functions does".
That is not true.
The insert call is, in all cases except when n == nullptr, the last thing the function does.
Adding a redundant return statement doesn't change that.
This:
void bar() {}
void foo()
{
return bar();
}
Is equivalent to this:
void bar() {}
void foo()
{
bar();
return;
}
Or this:
void bar() {}
void foo()
{
bar();
}
In absolutely every way.
In fact, the only reason we're allowed to do this at all, in a function returning void (remember, you're not actually returning any value here!), is to make implementing templates a bit easier.
And, in all of those examples, the compiler does not need to set up a fresh stack frame for the call to bar(). In the case of a recursive function, that gives you tail recursion.
Those returns are not doing anything in your code.
Simply remove the one "return;" line entirely.
Take the return off of the other two lines.
I'm no expert on tail recursion but I do know your code does the same thing and is simpler without the returns in it.
In your code all three returns do nothing and can be removed.
If a function returns void, then return is used only for terminating the function early. In your code there is nothing after all those returns, so they are superfluous.
On the other hand, if a function returns non-void, then it has to terminate via return (or exceptions or std::exit and so on). If control reaches the closing } of such a function, the behavior is undefined.
main() is an exception to this rule, reaching the closing } of main() automatically does return 0;.
Also, as #RetiredNinja said, "n needs to be a reference to a pointer". Otherwise the changes you make to n are discarded, and the memory allocated via new is leaked.
I've been trying to build a 2-3 node. The adding function is working properly and has been confirmed by me so far. The only problem is the find function, which is called to find an element inside the 2-3 node. It does not seem to be working at all. The match pointer inside the it does not take the returned valued from the find_rec method at all, even though I already assigned it. It's just getting a new given address whenever the function is called and I have no idea why it does that. Can anyone help me out ? and tell me what I did wrong ? Thank you
**LValue and RValue**
E LValue() {return _first._value;}
E RValue() {return _second._value;}
**find function**
// Assuming this set contains an element y such that (x == y),
// return a reference to y. Such a y must exist; if it does not an
// assertion will fail.
E& find(E& x)
{
// the match pointer is supposed to take
// returned pointer from the find_rec function
// Yet, it is not doing that at all.
E* match = find_rec(x, _root);
assert(match != nullptr);
return *match;
}
**find_rec function**
// Helper function: find recursion
// function returns a pointer
E* find_rec(E& x, BNode<E>* root)
{
if(root == nullptr)
return nullptr;
else
{
// 2-node
if(!root->IsThree())
{
if(x == root->LValue())
return &root->LValue();
else if (x < root->LValue())
return find_rec(x, root->GetLeft());
else
return find_rec(x, root->GetRight());
}
// 3-node
else
{
if(x == root->LValue())
return &root->LValue();
else if(x == root->RValue())
return &root->RValue();
else if(x < root->LValue())
return find_rec(x, root->GetLeft());
else if(x < root->RValue())
return find_rec(x, root->GetMiddle());
else
return find_rec(x, root->GetRight());
}
}
}
The code is clearly able to return a nullptr when the desired value is not present in the tree.
The moment it gets into that situation, the assert will trigger and the *match return would fail. I expect you need to change the function signature to provide a return type that allows for this case.
From the code seems you're returning the address of a local temporary.
I cannot be sure because the LValue() method declaration is not visible, but if it's returning the node content by value and not by reference then the find_rec function will just return garbage (the address of a temporary allocated on the stack).
A decent compiler should issue a warning for this, by the way.
I'd like to code a loop going through several instances of the same struct (named edg in my case) iterated by a certain function going from neighbor to neighbor until it returns an element that says STOP. I tried coding it using a NULL return but it doesn't work. What could I use?
Here is some code explaining it probably more accurately than my previous words:
My structure:
struct edg{
int i,j,k;
edg(int a, int b, int c){
i = a; j = b; k = c; //I'm adding a constructor to it
}
}
My iterating function:
edg neighbour(edg temp){
if(temp satisfies certain criterias){ return edg(new coordinates);}
else{ return NULL;}
}
My loop:
while(my_edg!=NULL){
my_edg = neighbour(my_edg);
}
I guess I could just pick a certain value of an edg define it as a rejection, and replace in my loop by:
while(my_edg!=edg_marked_as_rejection)
But is there another way to do so?
Note that your function:
edg neighbour(edg temp){
if(temp satisfies certain criterias){ return edg(new coordinates); }
else{ return NULL; }
}
returns an instance of edg by value thus trying to return NULL; is invalid (unless you've defined some custom conversion). NULL is a possible value when passing / returning by pointer, which in this case could mean changing the prototype of this function to:
edg* neighbour(edg temp) { ... }
however based on the semantics it would be more reasonable to either pass by reference and return a flag indicating success:
bool neighbour(const edg& temp, edg& result) {
if (...) {
result = ...;
return true;
}
return false;
}
or in case your condition "if(temp satisfies certain criterias)" should be met in most of cases and these criteria not being met is rather an exceptional state, you might also consider throwing an exception (instead of returning NULL).
A third option might be implementing a NULL object design pattern, meaning that instance of edg marked as "invalid" would be constructed and returned and caller would do something like:
edg n = neighbour(tmp);
if (!n.isValid()) {
...
}