You could use std::find_if algorithm:
Person * lookForName(vector<Person*> &names, const std::string& input)
{
auto it = std::find_if(names.begin(), names.end(),
&input{ return p->getName() == input; });
return it != names.end() ? *it : nullptr; // if iterator reaches names.end(), it's not found
}
For C++03 version:
struct isSameName
{
explicit isSameName(const std::string& name)
: name_(name)
{
}
bool operator()(Person* p)
{
return p->getName() == name_;
}
std::string name_;
};
Person * lookForName(vector<Person*> &names, const std::string& input)
{
vector<Person*>::iterator it = std::find_if(names.begin(), names.end(),
isSameName(input));
return it != names.end() ? *it : NULL;
}
Answer from billz on Stack Overflowqt - Can I return a NULL-Pointer in a C++ method? - Stack Overflow
Returning reference of NULL pointer
c++ - returning NULL pointer in C - Stack Overflow
pointers - When are you able to return NULL as the returning value of a C function? - Stack Overflow
Videos
You could use std::find_if algorithm:
Person * lookForName(vector<Person*> &names, const std::string& input)
{
auto it = std::find_if(names.begin(), names.end(),
&input{ return p->getName() == input; });
return it != names.end() ? *it : nullptr; // if iterator reaches names.end(), it's not found
}
For C++03 version:
struct isSameName
{
explicit isSameName(const std::string& name)
: name_(name)
{
}
bool operator()(Person* p)
{
return p->getName() == name_;
}
std::string name_;
};
Person * lookForName(vector<Person*> &names, const std::string& input)
{
vector<Person*>::iterator it = std::find_if(names.begin(), names.end(),
isSameName(input));
return it != names.end() ? *it : NULL;
}
If the name you are searching for is not at the first element, then you are not searching in the rest of the elements.
You need to do something like -
for (int i = 0; i<names.size(); i++){
Person* p = names[i];
if (p->getName() == input) {
return p;
// Placing break statement here has no meaning as it won't be executed.
}
}
// Flow reaches here if the name is not found in the vector. So, just return NULL
return NULL;
As Chris suggested, try using std::find_if algorithm.
You can return a null pointer if your function's return type is a pointer.
If the caller checks the return value and handles the case where the return value is null - then there shouldn't be any problem. if the caller tries to dereference this pointer, then problems do occur.
The fact that the function returns a pointer doesn't necessarily mean the developer needs to free the memory. the pointer could point to anything, including stack and global variables. The developer should look at the function's documentation to make sure what to do with the return value. Anyway, there is no problem in deleting null pointers, but again , one should look if she/he needs to deallocate something at the first place.
You can return a NULL pointer.
Do I have to free that pointer again?
delete is only necessary if you allocate space on the free store.
However, if you use C++11 or higher, I recommend the usage of nullptr instead of NULL. In this particular code, it doesn't provide a significant improvement but I consider it good style, also to draw the line between C and C++.
In following function I'm trying find a node in Binary tree that matches the key. I'm passing reference node pointer as smart pointer and this function returns a refernce to node pointer.
How can I return NULL ? As the return value of function is std::unique_ptr<node>& so it is supposed to return a reference.
std::unique_ptr<node>& BST::ReturnNodePrivate(const int& key, std::unique_ptr<node> &ptr){
if(NULL != ptr){
if(ptr->key == key){
return ptr;
}
}
else{
return NULL;
}
}
How can I return NULL ?
NULL is a pointer literal which is defined to contain a special value.
One possible definition is:
#define NULL ((void *)0)
For more detail you can read this faq
About const string& foo(), I believe you mean C++'s std::string.
std::string has no implicit constructor that initialize it with NULL pointer.
So you should use some exception or empty string to indicate an error to the caller. (If you are not throwing, you must return an std::string. Even if the object returned is local, its life is prolonged when kept in a local constant reference. But returning some other type and expecting an implicit conversion is not a good idea.)
Answer to your question: Because NULL is a literal, no temporary object may be created most of the time and actual value can be directly returned to the caller.
This function
const string& foo();
does not return a pointer. It returns a constant reference to an object of type std::string. So its return value may not be assigned to a pointer.
According to the C++ Standard
4.10 Pointer conversions [conv.ptr]
1 A null pointer constant is an integer literal (2.14.2) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4). A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t. [ Note: The resulting prvalue is not a null pointer value. —end note ]
So when you use null pointer constant defined with macro NULL it is assigned to the return pointer of the function that will contain null pointer value of type node *
NULL is a pointer value - or rather a null-pointer value.
NULL means that the function can't find where your pointer should point to - for example if you want to open a file, but it doesn't work your file pointer is returned as NULL. So you can test the value of a pointer and check to see if it worked or not.
If you are writing a routine
int length()
then you could return a negative value if length is unable to read the length of whatever you send it - this would be a way of indicating an error, because normally lengths can never be negative....
It is a matter of convention and you should clearly have one in your head and document it (at least in comments).
Sometimes a pointer really should always point to a valid address (see this intSwap example, both arguments should be valid pointers). At other times, it should either be such a valid address, or be NULL. Conceptually the pointer type is then by convention a sum type (between genuine pointer addresses and the special NULL value).
Notice that the C language does not have a type (or a notation) which enforces that some given pointer is always valid and non-null. BTW, with GCC specifically, you can annotate a function with __attribute__ using nonnull to express that a given argument is never null.
A typical example is FILE* pointers in <stdio.h>. The fopen function is documented to be able to return NULL (on failure), or some valid pointer. But the fprintf function is expecting a valid pointer (and passing NULL to it as the first argument is some undefined behavior, often a segmentation fault; and UB is really bad).
Some non-portable programs even use several "special" pointer values (which should not be dereferenced), e.g. (on Linux/x86-64) #define SPECIAL_SLOT (void*)((intptr_t)-1) (which we know that on Linux it is never a valid address). Then we could have the convention that a pointer is a valid pointer to a valid memory zone, or NULL or SPECIAL_SLOT (hence, if seen as an abstract data type, it is a sum type of two distinct invalid pointers NULL and SPECIAL_SLOT and the set of valid addresses). Another example is MAP_FAILURE as result of mmap(2) on Linux.
BTW, when using pointers in C to heap allocated data (indirectly obtained with malloc), you also need conventions about who is in charge of releasing the data (by using free, often thru a supplied function to free a data and all its internal stuff).
Good C programming requires many explicit conventions regarding pointers, and it is essential to understand them precisely and document them well. Look for example[s] into GTK. Read also about restrict.
Value of return type std::vector<int> cannot be nullptr.
The most straightforward way in this case is to return std::unique_ptr<std::vector<int>> instead - in this case it's possible to return nullptr.
Other options:
- throw an exception in case of fail
- use
optional<std::vector<int>>as return type (eitherboost::optionalorstd::optionalif your compiler has this C++17 feature) - return
boolparameter and havestd::vector<int>&as output parameter of function
The best way to go really depends on the use case. For example, if result vector of size 0 is equivalent to 'fail' - feel free to use this kind of knowledge in your code and just check if return vector is empty to know whether function failed or succeed.
In my practice I almost always stick to return optional (boost or std, depending on environment restriction).
Such interface is the most clear way to state the fact that 'result can either be present or not'.
To sum up - this is not a problem with the only one right solution. Possible options are listed above - and it's only a matter of your personal experience and environmental restrictions/convetions - which option to choose.
You could return a std::unique_ptr<std::vector<int>> and check that value, or throw an exception, or check vector.size() == 0 etc.
Since both are pointing to the same object, if either
objord_headeris changed, the change will be reflected in the other.
That is incorrect. If the contents of what they point to is changed, that change can be seen through either pointer but if one of them is changed so that it points to something different, the other will still point to the previous object.
Simple example:
int i = 10;
int j = 20;
int* ptr1 = &i;
int* ptr2 = ptr1;
At this point, both the pointers point to the same object, i. Value of i can be changed by:
Directly by assigning a value to
i.i = 15;Indirectly by assigning a value to where
ptr1points to.*ptr1 = 15;Indirectly by assigning a value to where
ptr2points to.*ptr2 = 15;
However, you can change where ptr1 points to by using:
ptr1 = &j;
Now, ptr1 points to j but ptr2 still points to i.
Any changes made to i will be visible through ptr2 but not ptr1.
Any changes made to j will be visible through ptr1 but not ptr2.
Isn't
objalso pointing to null, since both object were pointing to the same object?
The answer should be clear now. obj continues to point to what d_header used to point to. It is not NULL.
So what is the deal of returning a Null pointer?
The function does not necessarily return a NULL pointer. The function returns whatever d_header used to point to before it was changed to be nullptr. It could be a NULL pointer if d_header used to be NULL before the call to the function.
is
nullptrin this case would be the same asdelete?
No, it is not. There are two different operations. Assigning a pointer to nullptr does not automatically mean that delete gets called on the pointer. If you need to deallocate memory that a pointer points to, you'll have to call to call delete explicitly.
Q: "Isn't obj also pointing to null, since both object were pointing to the same object?"
No, both obj and d_heater contain addresses in memory. Changing one does not change the other. This is easy to see if you think about non-pointer variables:
int foo = 13;
int bar = foo;
foo = 42;
Obviously we know that bar still holds 13, and in the same way obj still holds the original address.
If you want obj to keep the same value as d_heater you can make it a reference, then obj and d_heater are the same variable they don't simply share the same value. We can see this again looking at non-pointer variables, but this time let's make bar a reference:
int foo = 13;
int& bar = foo;
foo = 42;
Now both foo and bar will equal 42. If you want to accomplish the same thing with obj make it a pointer reference:
WaterHeater*& obj = d_heater;
You can see a more detailed example here: http://ideone.com/I8CTba
Q. "Is nullptr in this case would be the same as delete?"
No, again d_heater is only an address. If you assign a new value to d_heater it is simply referencing a different point in memory. If by reassigning d_heater you lose the address of dynamically allocated memory that's very bad, it's known as a memory leak. To prevent leaking you must always release dynamically allocated memory before losing the last address to your dynamically allocated memory (call delete for memory allocated with new.)
That said, use of dynamic memory allocation is best left to the standard libraries, unless you really know what you're doing. So I'd strongly recommend you look at using auto-pointers. In C++11 those are unique_ptr and shared_ptr.
In C and C++, pointers are inherently unsafe, that is, when you dereference a pointer, it is your own responsibility to make sure it points somewhere valid; this is part of what "manual memory management" is about (as opposed to the automatic memory management schemes implemented in languages like Java, PHP, or the .NET runtime, which won't allow you to create invalid references without considerable effort).
A common solution that catches many errors is to set all pointers that don't point to anything as NULL (or, in correct C++, 0), and checking for that before accessing the pointer. Specifically, it is common practice to initialize all pointers to NULL (unless you already have something to point them at when you declare them), and set them to NULL when you delete or free() them (unless they go out of scope immediately after that). Example (in C, but also valid C++):
void fill_foo(int* foo) {
*foo = 23; // this will crash and burn if foo is NULL
}
A better version:
void fill_foo(int* foo) {
if (!foo) { // this is the NULL check
printf("This is wrong\n");
return;
}
*foo = 23;
}
Without the null check, passing a NULL pointer into this function will cause a segfault, and there is nothing you can do - the OS will simply kill your process and maybe core-dump or pop up a crash report dialog. With the null check in place, you can perform proper error handling and recover gracefully - correct the problem yourself, abort the current operation, write a log entry, notify the user, whatever is appropriate.
The other answers pretty much covered your exact question. A null check is made to be sure that the pointer you received actually points to a valid instance of a type (objects, primitives, etc).
I'm going to add my own piece of advice here, though. Avoid null checks. :) Null checks (and other forms of Defensive Programming) clutter code up, and actually make it more error prone than other error-handling techniques.
My favorite technique when it comes to object pointers is to use the Null Object pattern. That means returning a (pointer - or even better, reference to an) empty array or list instead of null, or returning an empty string ("") instead of null, or even the string "0" (or something equivalent to "nothing" in the context) where you expect it to be parsed to an integer.
As a bonus, here's a little something you might not have known about the null pointer, which was (first formally) implemented by C.A.R. Hoare for the Algol W language in 1965.
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
Returning NULL in case of success (the most simple case for success at that) is definitely contrary to what most people will expect.
Returning a pointer that the user has to manually destruct isn’t super great either. I’d suggest using C++11 unique_ptr but using C++11 may not be feasible in your case.
One thought I had is to make TestRoute private and have the Planner call it whenever it computes a new route.
If the test fails, return NULL, otherwise return the route.
What’s nice about this approach is that you can implement TestRoute however you (or your colleague) please, and the user of the class won’t need to know the details of how it is implemented. The user will just ask for a route from point A to point B and will be guaranteed it’s a valid route with refueling points so long as they don’t receive NULL.
You could also split your method into a few different methods if the performance hit isn’t too great.
For example, for TestRoute, have it return true if the route is possible, false if not.
bool TestRoute(const Route* r)
Have another method TestRouteNeedRefuel that returns true if the route will require refueling, false if not
bool TestRouteNeedRefuel(const Route* r)
Then have a final method, GenerateRefuelRoute that returns a new route with the proper refuel points
Route* TestRoute(const Route* r)
//use this if at all possible
std::unique_ptr<Route> TestRoute(const Route* r)
As far as performance goes, remember to profile before making assumptions. If your colleague is worried about copying Route more than needed (and he may have good reason to, as we don't know how expensive it is or what the target platform is) then clearly performance is an important requirement. I would suggest first implementing as clean an interface as can be done, profiling to find where the bottlenecks REALLY are, and then implementing a few speed hacks where necessary.
I would generally consider returning a pointer from a method in C++ a bad design, and mixing error states and payload data in the return value, too; this is a recipe for unmaintainable code.
Suggested change: Return the fail/success status as int value (or use ternary logic, e. g. boost::tribool), and pass the argument as non-const reference:
/** @returns
- 1 if a solution has been found. The argument will be updated.
- 0 if the request has been processed sucessfully,
but no (immediate) solution has been found.
The argument is not modified in this case.
- -1 if the request failed. The argument is not modified. */
int findSolution(MyClass& argument);
Usage example, leaving out premature optimization to avoid "unnecessary" copies:
MyClass objectToTest(originalUnmutableObject);
switch(findSolution(objectToTest))
{
case 1:
//Replace original with updated object, or whatever
break;
case 0:
//Nothing to do (?)
break;
case -1:
//Error handling
break;
default:
//Unexpected return value
assert(false);
}
An alternative, more sophisticated and reusable approach could be to bundle error state and object into a generic result class; this pattern was inspired by Rust. I leave the implementation of Result to you.
template<typename T>
class Result
{
public:
Result() = delete;
Result(int error);
Result(const T& data);
Result(T&& data);
//Methods
bool isOk() const;
bool isError(int error) const;
int error() const;
const T& data() const;
private:
//Variables
int m_error = 0;
T m_data;
};
...
Result<MyClass> findSolution(const MyClass& argument)
{
int errorCode = 0;
...
if(errorCode != 0)
return Result(errorCode);
else if(solutionFound)
//Error code of result will be 0, Result::isOk() == true
return Result(update(argument, solution));
else
//Error code of result will be 1, Result::isOk() == false
return Result(1);
}
I am very sure that someone told me once that NULL is defined as a pointer to void. I leafed through the K&R, and NULL was just said to be interchangeable with zero.
But either way, if I have a function that returns a 3d char array (array of arrays of strings), can I then return NULL if something goes wrong? will it be a valid return type?
Many functions that return pointers return NULL if something goes wrong - fopen for instance where you check for NULL and then perror.
But I am confused about multi-dimensional pointers.
I mean, I know that they are technically just pointers. I am unsure what the multiple asterisks do except tell the programmer how many dimensions there are. Hmmm Is this the solution?
Comments?