Check if container of shared_ptr contains a pointer? - c++

Using Observer pattern. I have a class, called Monitor for example, that is monitoring a collection of objects. The class is an Observer and each object in it's collection is a Subject. Currently the collection is implemented as a std::list of shared_ptr. In the Update method of the Monitor class I want to check if the update is coming from one of the objects in it's collection.
std::list<SomeSharedPointer> items_;
...
void Monitor::Update(Subject *subject)
{
if(subject == something_)
{
DoSomething();
}
else if
??
// if subject is one of the objects in our collection then do something..
}
Subject here is a raw pointer and my collection is a list of shared_ptr. How can I effectively check if the subject coming in is any one of the objects in my collection?
(Note my compiler, msvc, supports lambdas if there is an algorithmic solution requiring one)
UPDATE
I should add that I realize I can use a for loop over the container, but I'm wondering if there's a snazzier way.
UPDATE 2
SomeSharedPointer is a typedef for std::shared_ptr<SomeType> where SomeType derives from abstract class Subject (standard Observer pattern implementation). SomeType will at some point call Notify() which will call the Update() method for each observer.

auto i = std::find_if(items_.begin(), items_.end(),
[=](const SomeSharedPointer& x) { return x.get() == subject; });
if (i != c.end())
{
// Object found, and i is an iterator pointing to it
}
A little helper method can make this more readable:
typedef std::list<SomeSharedPtr> ObserverCollection;
// You can also add a const version if needed
ObserverCollection::iterator find_observer(Subject* s)
{
return std::find_if(items_.begin(), items_.end(),
[=](const SomeSharedPointer& x) { return x.get() == s; });
}
Then, you use it like this if you need the iterator
auto i = find_observer(subject);
if (i != items_.end())
{
// Object found
}
or simply like this if you don't:
if (find_observer(subject) != items_.end())
{
...
}

If you don't have C++11 support for auto, declare the iterator the old fashioned way
for (auto iter = items_.begin(); iter != items_.end(); ++iter)
{
if (subject == iter->get())
{
.. do stuff ..
}
}
Shared pointer has a .get() function that returns the pointer.

Since you said that the observer needs to make a decision based on a state of items it is monitoring, then you should add a method to the base class (Subject in your question) which returns an enum defining the item's state. Then based on the state, add a switch in the update method:
enum State{ STATE_1, STATE_2 };
void Monitor::Update(Subject *subject)
{
switch( subject->getState() )
{
case STATE_1:
// do something 1
break;
case STATE_2:
// do something 2
break;
default:
//error
}
}

If possible, you could consider changing your container to something that gives you better search behavior. For instance, you could use a std::set. It costs more per insertion, but faster per lookup. Or, std::unordered_set. Both insertion and lookup are fast, but iteration is likely slower. To achieve proper comparison, you can create a helper class to enable converting your raw pointer into a shared pointer that has an no-op deleter.
template <typename T>
struct unshared_ptr {
std::shared_ptr<T> p_;
unshared_ptr (T *p) : p_(p, [](...){}) {}
operator const std::shared_ptr<T> & () const { return p_; }
operator T * () const { return p_.get(); }
};
If your container supported the find method, then:
typedef unshared_ptr<SomeType> unshared_some;
if (items_.end() != items_.find(unshared_some(subject))) {
DoSomething();
}
Try it online!
If you are sticking with std::list, you can abuse the remove_if method by passing in a predicate that always returns false, but performs your matching test.
bool matched = false;
auto pred = [subject, &matched](SomeSharedPtr &v) -> bool {
if (!matched && v.get() == subject) {
matched = true;
}
return false;
};
items_.remove_if(pred);
if (matched) {
DoSomething();
} //...

Related

How to handle a function that is not guaranteed to return anything?

I have a class that stores & manages a vector containing a number of objects.
I'm finding myself writing a number of functions similar to the following:
Object* ObjectManager::getObject(std::string name){
for(auto it = object_store.begin(); it != object_store.end(); ++it){
if(it->isCalled(name))
return &(*it)
}
return nullptr;
}
I think I would rather return by reference, as here the caller would have to remember to check for null! Is there a way I can change my design to better handle this?
Your alternatives are outlined below
Change your API to the following
object_manager.execute_if_has_object("something", [](auto& object) {
use_object(object);
});
This API is much easier to use, conveys intent perfectly and removes the thought process of error handling, return types, etc from the user's mind
Throw an exception.
Object& ObjectManager::getObject(const std::string& name){
for(auto& object : object_store){
if(object.isCalled(name))
return object;
}
// throw an exception
throw std::runtime_error{"Object not found"};
}
Return a bool, pass the Object by reference and get a copy
bool ObjectManager::getObject(const std::string& name, Object& object_out){
for(auto& object : object_store){
if(object.isCalled(name)) {
object_out = object;
return true;
}
}
return false;
}
Let the user do the finding
auto iter = std::find(object_store.begin(), object_store.end(), [&name](auto& element) {
return element.isCalled(name);
}
if (iter != object_store.end()) { ... }
Also
Pass that string by const reference. When C++17 is available change that const reference to a std::string_view
Use range based for loops in this situation, they are a more readable alternative for what you are doing
Look at the design of STL (e.g. find function), it is not at all bad to return the iterator your just searched for, and return .end() otherwise.
auto ObjectManager::getObject(std::string name){
for(auto it = object_store.begin(); it != object_store.end(); ++it){
if(it->isCalled(name))
return it;
}
return object_store.end();
}
More: Of course object_store.end() may be inaccessible from outside the class but that is not an excuse, because you can do this (note the more slick code also)
auto ObjectManager::getObject(std::string name){
auto it = object_store.begin();
while(not it->isCalled(name)) ++it;
return it;
}
auto ObjectManager::nullObject(){return object_store.end();}
Less code is better code. You can use it like this:
auto result = *om.getObject("pizza"); // search, not check (if you know what you are doing)
or
auto it = om.getObject("pizza");
if(it != om.nullObject() ){ ... do something with *it... }
or
auto it = om.getObject("pizza");
if(it != om.nullObject() ){ ... do something with *it... }
else throw java_like_ridiculous_error("I can't find the object, the universe will collapse and it will jump to another plane of existence");
Of course at this point it is better to call the functions findOject and noposObject and also question why not using directly std::find on the object_store container.
I think you are already handling the return value properly and your current solution is optimal.
The fact is you can not avoid checking for something in order to discover if your find operation succeeded. If you throw an exception then your try{}catch{} is your check. Also an exception should not be used when not finding an item is a legitimate result. If you return a bool and use an out parameter you have made the situation more complicated to do the same job. Same with returning an iterator. A std::optional returns values.
So IMO you can't improve upon returning a pointer you can just make the same job more complicated.
Solution alternative to exceptions or optional is to implement a "Null object" - which can be used as a regular object, but will "do nothing". Depends on the case, sometimes it can be used as is and does not require to be checked (explicitly) - especially in cases where ignoring the "not found" situation is acceptable.
(the null object can be a static global, so it is also possible to return a reference to it)
Even if a check is needed, an isNull() method can be implemented, which returns true for the null object and false for a valid object (or there can be isValid() method, etc.).
Example:
class Object {
public:
virtual void doSomething();
};
class NullObject: public Object {
public:
virtual void doSomething() {
// doing nothing - ignoring the null object
}
};
class ObjectManager {
public:
Object& getObject(const std::string& name);
private:
static NullObject s_nullObject;
};
Object& ObjectManager::getObject(const std::string& name){
for(auto it = object_store.begin(); it != object_store.end(); ++it){
if(it->isCalled(name))
return *it;
}
return s_nullObject;
}
ObjectManager mgr;
Object& obj = mgr.getObject(name);
obj.doSomething(); // does nothing if the object is NullObject
// (without having to check!)

Return a unique_ptr by reference

So I've solved this problem, but I need your opinion if what I did is best practice.
A simple class holds a vector of unique_ptrs to order objects. I will explain the member variable null_unique below.
class order_collection {
typedef std::unique_ptr<order> ord_ptr;
typedef std::vector<ord_ptr> ord_ptr_vec;
ord_ptr_vec orders;
ord_ptr null_unique;
public:
...
const ord_ptr & find_order(std::string);
....
So I need the users of this class to get access to the order unique_ptr if found. However I'm not going to move the object out of the vector so I'm returning the unique_ptr as const ref. My implementation of the find_order method:
const order_collection::ord_ptr & order_collection::find_order(std::string id) {
auto it = std::find_if(orders.begin(),orders.end(),
[&](const order_collection::ord_ptr & sptr) {
return sptr->getId() == id;
});
if (it == orders.end())
return null_unique; // can't return nullptr here
return *it;
}
Since I'm returning by reference I can't return a nullptr. If I try to do so, I get warning : returning reference to a temporary. And if nothing is found the program crashes. So I added a unique_ptr<order> member variable called null_unique and I return it when find doesn't find an order. This solves the problem and warning is gone and doesn't crash when no order is found.
However I'm doubting my solution as it make my class ugly. Is this the best practice for handling this situation?
You should only return and accept smart pointers when you care about their ownership semantics. If you only care about what they're pointing to, you should instead return a reference or a raw pointer.
Since you're returning a dummy null_unique, it is clear that the caller of the method doesn't care about the ownership semantics. You can also have a null state: you should therefore return a raw pointer:
order* order_collection::find_order(std::string id) {
auto it = std::find_if(orders.begin(),orders.end(),
[&](const order_collection::ord_ptr & sptr) {
return sptr->getId() == id;
});
if (it == orders.end())
return nullptr;
return it->get();
}
It doesn't really make sense to return a unique_ptr here, reference or otherwise. A unique_ptr implies ownership over the object, and those aren't really the semantics being conveyed by this code.
As suggested in the comments, simply returning a raw pointer is fine here, provided that your Project Design explicitly prohibits you or anyone on your team from calling delete or delete[] outside the context of the destructor of a Resource-owning object.
Alternatively, if you either have access to Boost or C++17, a std::optional<std::reference_wrapper<order>> might be the ideal solution.
std::optional<std::reference_wrapper<order>> order_collection::find_order(std::string id) {
auto it = std::find_if(orders.begin(),orders.end(),
[&](const order_collection::ord_ptr & sptr) {
return sptr->getId() == id;
});
if (it == orders.end())
return {}; //empty optional object
return **it; //will implicitly convert to the correct object type.
}
/*...*/
void func() {
auto opt = collection.find_order("blah blah blah");
if(!opt) return;
order & ord = opt->get();
/*Do whatever*/
}
(EDIT: In testing on the most recent version of MSVC 2017, it looks like std::reference_wrapper<T> will happily do an implicit conversion to T& if you tell it to. So replacing opt->get() with *opt should work exactly the same.)
As long as I'm here, I might point out that a std::vector<std::unique_ptr<type>> object has a very "Code Smell" sense to it. std::vector<type> implies ownership of the object as is, so unless you have a good reason to prefer this (maybe the objects are large, unmovable/uncopyable, and you need to insert and remove entries frequently? Maybe this is a polymorphic type?), you're probably better off reducing this to a simple std::vector.
EDIT:
The boost version is subtly different, because boost::optional has no restrictions against "optional references", which are specifically forbidden by the C++ Standard Library's version of std::optional. The boost version is actually going to be slightly simpler:
//return type changes, nothing else changes
boost::optional<order&> order_collection::find_order(std::string id) {
auto it = std::find_if(orders.begin(),orders.end(),
[&](const order_collection::ord_ptr & sptr) {
return sptr->getId() == id;
});
if (it == orders.end())
return {}; //empty optional object
return **it; //will implicitly convert to the correct object type.
}
/*...*/
//Instead of calling opt->get(), we use *opt instead.
void func() {
auto opt = collection.find_order("blah blah blah");
if(!opt) return;
order & ord = *opt;
/*Do whatever*/
}

Const lock wrapper for STL containers

I'm trying to create a wrapper for an std::vector (or any other container from STL, if possible) that can "lock" and "unlock" the const state of a vector that it's holding.
For example, if I create an object of that wrapper, I want to be able to do something like this:
int main()
{
ConstLockVectorWrapper<int> myWrapper(std::vector<int>{}); // Here I pass an empty vector in the constructor parameters,
// which means that my wrapper will be holding an empty vector
// By default the vector inside my wrapper is not locked,
// I can change its size and the values that it holds
myWrapper.get().push_back(10); // ok
myWrapper.get().push_back(20); // ok
myWrapper.get().at(0) = 5; // ok
print(myWrapper.get()); // Prints 5 20
myWrapper.lock(); // Now I made the vector inside my wrapper unchangable
myWrapper.get().push_back(30); // error, the vector is locked
myWrapper.get().at(0) = 55; // error
print(myWrapper.get()); // ok
myWrapper.unlock(); // Now I can change my vector's size and its values again
_getch();
return 0;
}
The only solution (that's not working, unfortunately) I've got, is to create a const reference (const std::vector<T> &) and a regular reference (td::vector<T> &) inside a wrapper class, and bound them to the main vector in our wrapper class.
So, this is what I've done:
template <typename T>
class ConstLockVectorWrapper {
public:
ConstLockVectorWrapper(const std::vector<T> & vec)
: wrappedVector(vec), wrappedVectorRef(wrappedVector), wrappedVectorConstRef(wrappedVector), constLock(false)
{}
void lock()
{
if (constLock) // if the vector is already locked, we just exit the function
return;
// else we lock the vector
constLock = true;
}
void unlock()
{
if (!constLock) // if the vector is already unlocked (changable), we just exit the function
return;
// else we unlock the vector
constLock = false;
}
return_type get() // I need to return a const std::vector<T> & if constLock == true, and std::vector<T> & otherwise, what return type should I put in here?
{
if (constLock)
return wrappedVectorConstRef;
else
return wrappedVectorRef;
}
private:
bool constLock;
std::vector<T> wrappedVector;
// refs
std::vector<T> & wrappedVectorRef;
const std::vector<T> & wrappedVectorConstRef;
};
Of course, it doesn't work. Just because I don't know what to put in the return type of my get() fucntion.
I've tried using trailing return type, didn't work:
template <typename T>
class ConstLockVectorWrapper {
public:
// ...
private:
bool constLock;
std::vector<T> wrappedVector;
// refs
std::vector<T> & wrappedVectorRef;
const std::vector<T> & wrappedVectorConstRef;
public:
auto get() -> decltype((constLock ? wrappedVectorConstRef : wrappedVectorRef))
{
if (constLock)
return wrappedVectorConstRef;
else
return wrappedVectorRef;
}
};
I can't come up with any solution that will actually work, because I'm not so good at C++ yet.
So I'm asking for your help with my problem. Any suggestions or hints to solve this problem would be appreciated!
Thanks
PS
My main goal is to make my wrapper container-type-independent, so it can "lock" and "unlock" the const state of the container it's holding, independently of its type.
And here's the print() function I used in the first code snippet:
template <typename Container>
void print(const Container & c)
{
for (const auto & var : c)
std::cout << var << std::endl;
}
Fundamentally, a method always returns the same thing. The same type. Every time. It's not possible, in C++, to have a method sometimes return one type, and another type at other times. C++ does not work this way.
So, the initial approach would be to have get() return a proxy object with a state. Using, roughly, the same classes and names from your question:
class return_type {
bool is_const;
std::vector<T> &wrapped_vec;
public:
return_type(bool is_constArg,
std::vector<T> &wrapped_vecArg)
: is_const(is_constArg), wrapped_vec(wrapped_vecArg)
{
}
void push_back(T &&t)
{
if (is_const)
throw std::runtime_error(); // Or, whatever...
wrapped_vec.push_back(std::forward<T>(t));
}
// return_type will have to implement, and baby-sit all other
// methods you wish to invoke on the underlying vector.
};
return_type get()
{
return return_type(constLock);
}
This is simple, but crude and somewhat tedious. You would have to implement every std::vector method you need to use in the return_type proxy.
A better approach would be to take advantage of C++11 lambdas. This will avoid the need to reimplement every wheel, at an expense of some additional code bloat. But, big deal. RAM is cheap, these days. Instead of get() and return_type, you will now be implementing two template methods in your wrapper: get_const() and get_mutable(). Each one of them takes a lambda parameter and invokes it and, if all goes well, passing it the wrapped vector as an argument:
template<typename lambda>
void get_mutable(lambda &&l)
{
if (constLock)
throw std::runtime_error(); // Or, whatever...
l(wrapped_vec);
}
template<typename lambda>
void get_const(lambda &&l)
{
l(const_cast<const std::vector<T> &>(wrapped_vec));
}
The only thing you now need to decide is whether you need access a mutable or a constant vector, and pick the right getter:
myWrapper.get_mutable( [&](std::vector<int> &v) { v.push_back(10); } );
get_mutable() throws an exception if the vector is locked at this time. Otherwise it passes the vector to your lambda. Your lambda does whatever the heck it wants with it, which can be push_back(), or anything else, then returns.
But if you only need read-only access to the vector, use get_const():
int s;
myWrapper.get_const( [&](const std::vector<int> &v) { s=v.size(); } );
Note that get_const() takes care to const_cast the vector, before invoking the lambda, so the lambda will not be able to modify it. This will be enforced at compile-time.
With some additional work, it would also be possible to clean this up a little bit, and have the getter also return whatever lambda returns to the caller, making it possible to do something like this:
int s=myWrapper.get_const( [&](const std::vector<int> &v) { return v.size(); } );
It's possible to have get_const() and get_mutable() be smart enough to figure out if the lambda returns something, and happily pass it back to the caller, whatever it is. And how to do that, I suppose, will have to be another question on stackoverflow.com
P.S. If you don't have C++11, you can just have get_const() and get_mutable() return the wrapped vector (with get_mutable() verifying that it's not locked). This really accomplishes the same thing. The key point is that due to the way that C++ works, you will have to disambiguate, in advance, whether you need constant or mutable access.
I was working on a similar problem a while back. In multithreaded environment sometimes its more efficient to have different types of lock depending on whether you are reading or writing. But the locking is entirely cooperative. It is possible to obtain a read-only lock but still accidentally write to the object.
One solution I am exploring is, instead of obtaining a read-only lock from an object, getting a read-only wrapper of my object so that not only is the object read-only locked it is also only possible to call read-only (const) methods on the object.
The basic wrapper I used was something like this:
template<typename T>
class ConstWrapper
{
T& v;
public:
ConstWrapper(T& v): v(v) {}
T const& operator* () const { return v; } // return const reference
T const* operator->() const { return &v;} // return const pointer
};
By overloading the * and -> operators you get a kind of pass through ability to call the enclosed objects methods - but using pointer semantics (though its not a pointer).
std::vector<int> v {1, 2, 3, 4}; // not const
ConstWrapper<std::vector<int>> cv(v); // const wrapper
std::cout << cv->at(0) << '\n'; // okay at() is a const method
cv->push_back(8); // ILLEGAL!! push_back() is not a const method

Creating a map for millions of objects in C++

I have an abstract class called Object that has a few virtual functions, one of which is a function that will retrieve the id of an Object.
Currently, I am using a std::vector<Object> to store tens of millions of these objects. Unfortunately, adding, copying, or removing from this is painfully slow.
I wanted to create a hash map that could maybe have the Object->id as the key, and maybe the object itself as a value? Or is there some type of data structure that would allow for easy insertion and removal like a std::vector but would be faster for tens of millions of objects?
I would want the class to end up looking something like this outline:
stl::container<Objects*> obj_container;
DataContainer::DataContainer()
: stl::container(initialized_here)
{}
DataContainer::addObject(Object* object)
{
obj_container.insert(object);
}
DataContainer::removeObject(Object* object)
{
obj_container.remove(object);
}
DataContainer::preSort()
{
obj_container.sort_by_id();
}
DataContainer::getObject(Object* object)
{
if(!obj_container.contains(object)) { return; }
binary_search(object);
}
Is there anything really fast at processing large amounts of these objects, or is there anything really fast that could possibly use an unsigned integer id from an object to process the data?
Also, my class would get pre-sorted, so every object would be sorted by ID before being added to the container. Then I would do a binary search on the data by ID.
You probably could use std::set (if the id-s have some order and are unique for it) or std::unordered_set and I would suggest you make it a component of your container, not derive your container from it. You'll better have a way of constructing a local fake Object with only its id ...
class Object {
friend class BigContainer;
unsigned long _id;
// other fields;
// your constructors
public:
unsigned long id() const { return _id; };
private:
Object(unsigned long pseudoid); // construct a fake object
};
struct LessById {
bool operator () (const Object &ob1, const Object& ob2)
{ return ob1.id() < ob2.id(); };
bool operator () (const Object &ob, unsigned long idl)
{ return ob1.id() < idl;
};
class BigContainer {
std::set<Object,LessById> set;
public:
// add members, constructors, destructors, etc...
bool contains(unsigned long id) const {
Object fakeobj{id};
if (set.find(fakeobj) != set.end()) return true;
return false;
};
const Object* find_by_id(unsigned long id) const {
Object fakeobj{id};
auto p = set.find(fakeobj);
if (p != set.end()) return &(*p);
return nullptr;
};
bool contains(const Object& ob) const {
if (set.find(ob) != set.end()) return true;
return false;
};
void add(const Object&ob) const {
Object fakeobj{id};
auto p = set.find(fakeobj);
if (p == set.end()) set.insert(ob);
}
void remove(unsigned long id) const {
Object fakeobj{id};
auto p = set.find(fakeobj);
if (p != set.end()) set.erase(p);
}
};
If you want a set of pointers use a set of some smart pointers and adapt the scheme above.
If the Object is big and you have trouble in defining a way of constructing efficiently local fake objects for a given id, define a super struct BoxedId { unsigned long id; BoxedId(unsigned long l): id(l) {}; }, declare internally a std::set<std::shared_ptr<BoxedId>,BoxedLessById> make class Object : public BoxedId, etc...
BTW, since Object has virtual methods you probably will subclass it and you need to have a set of pointers. You need to define a pointer policy (are every actual instances of sub-classes of Object-s in your Container) and use some smart pointer.... You need to define who is in charge of delete-ing your Object-s (who owns the pointer). Is it only the unique BigContainer.
Read the C++11 rule of five.
Please have a look at this site : http://www.cs.northwestern.edu/~riesbeck/programming/c++/stl-summary.html
It shows the time complexity of each operation of each STL.
First be clear about your requirement and then choose particular STL wisely by comparing its time complexity shown in above link.

Returning a "NULL reference" in C++?

In dynamically typed languages like JavaScript or PHP, I often do functions such as:
function getSomething(name) {
if (content_[name]) return content_[name];
return null; // doesn't exist
}
I return an object if it exists or null if not.
What would be the equivalent in C++ using references? Is there any recommended pattern in general? I saw some frameworks having an isNull() method for this purpose:
SomeResource SomeClass::getSomething(std::string name) {
if (content_.find(name) != content_.end()) return content_[name];
SomeResource output; // Create a "null" resource
return output;
}
Then the caller would check the resource that way:
SomeResource r = obj.getSomething("something");
if (!r.isNull()) {
// OK
} else {
// NOT OK
}
However, having to implement this kind of magic method for each class seems heavy. Also it doesn't seem obvious when the internal state of the object should be set from "null" to "not null".
Is there any alternative to this pattern? I already know it can be done using pointers, but I am wondering how/if it can be done with references. Or should I give up on returning "null" objects in C++ and use some C++-specific pattern? Any suggestion on the proper way to do that would be appreciated.
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::pair with a bool to 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".
One nice and relatively non-intrusive approach, which avoids the problem if implementing special methods for all types, is that used with boost.optional. It is essentially a template wrapper which allows you to check whether the value held is "valid" or not.
BTW I think this is well explained in the docs, but beware of boost::optional of bool, this is a construction which is hard to interpret.
Edit: The question asks about "NULL reference", but the code snippet has a function that returns by value. If that function indeed returned a reference:
const someResource& getSomething(const std::string& name) const ; // and possibly non-const version
then the function would only make sense if the someResource being referred to had a lifetime at least as long as that of the object returning the reference (otherwise you woul dhave a dangling reference). In this case, it seems perfectly fine to return a pointer:
const someResource* getSomething(const std::string& name) const; // and possibly non-const version
but you have to make it absolutely clear that the caller does not take ownership of the pointer and should not attempt to delete it.
I can think of a few ways to handle this:
As others suggested, use boost::optional
Make the object have a state that indicates it is not valid (Yuk!)
Use pointer instead of reference
Have a special instance of the class that is the null object
Throw an exception to indicate failure (not always applicable)
unlike Java and C# in C++ reference object can't be null.
so I would advice 2 methods I use in this case.
1 - instead of reference use a type which have a null such as std::shared_ptr
2 - get the reference as a out-parameter and return Boolean for success.
bool SomeClass::getSomething(std::string name, SomeResource& outParam) {
if (content_.find(name) != content_.end())
{
outParam = content_[name];
return true;
}
return false;
}
This code below demonstrates how to return "invalid" references; it is just a different way of using pointers (the conventional method).
Not recommended that you use this in code that will be used by others, since the expectation is that functions that return references always return valid references.
#include <iostream>
#include <cstddef>
#define Nothing(Type) *(Type*)nullptr
//#define Nothing(Type) *(Type*)0
struct A { int i; };
struct B
{
A a[5];
B() { for (int i=0;i<5;i++) a[i].i=i+1; }
A& GetA(int n)
{
if ((n>=0)&&(n<5)) return a[n];
else return Nothing(A);
}
};
int main()
{
B b;
for (int i=3;i<7;i++)
{
A &ra=b.GetA(i);
if (!&ra) std::cout << i << ": ra=nothing\n";
else std::cout << i << ": ra=" << ra.i << "\n";
}
return 0;
}
The macro Nothing(Type) returns a value, in this case that represented by nullptr - you can as well use 0, to which the reference's address is set. This address can now be checked as-if you have been using pointers.
From C++17 on, you can use the native std::optional (here) in the following way:
std::optional<SomeResource> SomeClass::getSomething(std::string name) {
if (content_.find(name) != content_.end()) return content_[name];
return std::nullopt;
}
Here are a couple of ideas:
Alternative 1:
class Nullable
{
private:
bool m_bIsNull;
protected:
Nullable(bool bIsNull) : m_bIsNull(bIsNull) {}
void setNull(bool bIsNull) { m_bIsNull = bIsNull; }
public:
bool isNull();
};
class SomeResource : public Nullable
{
public:
SomeResource() : Nullable(true) {}
SomeResource(...) : Nullable(false) { ... }
...
};
Alternative 2:
template<class T>
struct Nullable<T>
{
Nullable(const T& value_) : value(value_), isNull(false) {}
Nullable() : isNull(true) {}
T value;
bool isNull;
};
Yet another option - one that I have used from time to time for when you don't really want a "null" object returned but instead an "empty/invalid" object will do:
// List of things
std::vector<some_struct> list_of_things;
// An emtpy / invalid instance of some_struct
some_struct empty_struct{"invalid"};
const some_struct &get_thing(int index)
{
// If the index is valid then return the ref to the item index'ed
if (index <= list_of_things.size())
{
return list_of_things[index];
}
// Index is out of range, return a reference to the invalid/empty instance
return empty_struct; // doesn't exist
}
Its quite simple and (depending on what you are doing with it at the other end) can avoid the need to do null pointer checks on the other side. For example if you are generating some lists of thing, e.g:
for (const auto &sub_item : get_thing(2).sub_list())
{
// If the returned item from get_thing is the empty one then the sub list will
// be empty - no need to bother with nullptr checks etc... (in this case)
}