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 OverflowYou 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.
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 ?
Videos
I have a function that returns a valid pointer if an operation succeeds else a null pointer. Is it better to wrap pointer around the optional?
T* get(); // 1 optional<T*> get(). // 2
is 2 better than 1 as former can lead to null pointer dereferencing?
In this function what exactly is being returned? It's not complete yet but I am trying to make a single linked list with k as the head but I don't understand nullptr.
SLinkedList<E>* SearchTree<E>::findPath(const K& k) {
SLinkedList<Entry<string, string>> sll;
sll.addFront(k);
return nullptr;
}You cannot do this during references, as they should never be NULL. There are basically three options, one using a pointer, the others using value semantics.
With a pointer (note: this requires that the resource doesn't get destructed while the caller has a pointer to it; also make sure the caller knows it doesn't need to delete the object):
SomeResource* SomeClass::getSomething(std::string name) { std::map<std::string, SomeResource>::iterator it = content_.find(name); if (it != content_.end()) return &(*it); return NULL; }Using
std::pairwith aboolto indicate if the item is valid or not (note: requires that SomeResource has an appropriate default constructor and is not expensive to construct):std::pair<SomeResource, bool> SomeClass::getSomething(std::string name) { std::map<std::string, SomeResource>::iterator it = content_.find(name); if (it != content_.end()) return std::make_pair(*it, true); return std::make_pair(SomeResource(), false); }Using
boost::optional:boost::optional<SomeResource> SomeClass::getSomething(std::string name) { std::map<std::string, SomeResource>::iterator it = content_.find(name); if (it != content_.end()) return *it; return boost::optional<SomeResource>(); }
If you want value semantics and have the ability to use Boost, I'd recommend option three. The primary advantage of boost::optional over std::pair is that an unitialized boost::optional value doesn't construct the type its encapsulating. This means it works for types that have no default constructor and saves time/memory for types with a non-trivial default constructor.
I also modified your example so you're not searching the map twice (by reusing the iterator).
Why "besides using pointers"? Using pointers is the way you do it in C++. Unless you define some "optional" type which has something like the isNull() function you mentioned. (or use an existing one, like boost::optional)
References are designed, and guaranteed, to never be null. Asking "so how do I make them null" is nonsensical. You use pointers when you need a "nullable reference".
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.
In C++, references can't be null. If you want to optionally return null if nothing is found, you need to return a pointer, not a reference:
Attr *getAttribute(const string& attribute_name) const {
//search collection
//if found at i
return &attributes[i];
//if not found
return nullptr;
}
Otherwise, if you insist on returning by reference, then you should throw an exception if the attribute isn't found.
(By the way, I'm a little worried about your method being const and returning a non-const attribute. For philosophical reasons, I'd suggest returning const Attr *. If you also may want to modify this attribute, you can overload with a non-const method returning a non-const attribute as well.)
There are several possible answers here. You want to return something that might exist. Here are some options, ranging from my least preferred to most preferred:
Return by reference, and signal can-not-find by exception.
Attr& getAttribute(const string& attribute_name) const { //search collection //if found at i return attributes[i]; //if not found throw no_such_attribute_error; }
It's likely that not finding attributes is a normal part of execution, and hence not very exceptional. The handling for this would be noisy. A null value cannot be returned because it's undefined behaviour to have null references.
Return by pointer
Attr* getAttribute(const string& attribute_name) const { //search collection //if found at i return &attributes[i]; //if not found return nullptr; }
It's easy to forget to check whether a result from getAttribute would be a non-NULL pointer, and is an easy source of bugs.
Use Boost.Optional
boost::optional<Attr&> getAttribute(const string& attribute_name) const { //search collection //if found at i return attributes[i]; //if not found return boost::optional<Attr&>(); }
A boost::optional signifies exactly what is going on here, and has easy methods for inspecting whether such an attribute was found.
Side note: std::optional was recently voted into C++17, so this will be a "standard" thing in the near future.
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);
}
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.