patterncppMinor
Null Object Pattern for STL Types
Viewed 0 times
stlnullfortypesobjectpattern
Problem
Background
In C++ unlike other OOP languages, we do not have a Base Class from where All Classes are derived. I understand in MFC and pre STL, some Compilers did had a similar model, so lets leave it out of the discussion and focus on what the standard provides.
In C++11,
Using Naked Pointers were prone to errors so Smart Pointers were introduced as a remedy for the unavoidable evil.
Use Case
I have a function which should return something that would indicate Null Object when no data was found or if it found needs to return the data. I would like to know, if C++11 has an elegant way of writing the below code, considering, the template types are painful to read.
Code
One option is to use a
In C++ unlike other OOP languages, we do not have a Base Class from where All Classes are derived. I understand in MFC and pre STL, some Compilers did had a similar model, so lets leave it out of the discussion and focus on what the standard provides.
In C++11,
auto was introduced to derive the type from rvalue just another way of type deduction of templates. This was a huge relief when one has to write long list of types with all template parameters.Using Naked Pointers were prone to errors so Smart Pointers were introduced as a remedy for the unavoidable evil.
Use Case
I have a function which should return something that would indicate Null Object when no data was found or if it found needs to return the data. I would like to know, if C++11 has an elegant way of writing the below code, considering, the template types are painful to read.
Code
std::unique_ptr > CCOMErrorHandler::PopError()
{
unique_ptr > error = nullptr;
if (!m_lstErrors.empty())
{
error = std::unique_ptr >(new std::tuple(m_lstErrors.front()));
if (error)
{
m_lstErrors.pop_front();
}
}
return(error);
}One option is to use a
typedef or macro replacement, but generally am not a big FAN as that keeps polluting namespace though you may have to use to few times in your code often only once.Solution
The first question is, why are you using pointers in the first place here? Allocation with
Many STL containers use either an error-code approach, that is, they return a
directly with iterators, and return an iterator to
Though it is not contained in the C++ standard library at the moment (it is slated for inclusion in C++14),
cppreference has an API reference for
As for the complaint about template types, you can always wrap them in another namespace to help prevent pollution:
new should only be used when required. Perhaps it is in this case, but I'd rethink your design. Are the errors polymorphic? If so, why? If not, why do you need to use pointers?Many STL containers use either an error-code approach, that is, they return a
std::pair, where the bool represents success/failure, or they dealdirectly with iterators, and return an iterator to
end() in the case of failure. Depending on the type of m_lstErrors, this could be a possibility (although obviously this won't work for a container adapter like std::stack). Though it is not contained in the C++ standard library at the moment (it is slated for inclusion in C++14),
std::optional was basically made for this purpose. In fact, it can be written using only C++11 features (and there's a reference implementation you could use here). Boost also contains a boost::optional type, although this lacks things such as move semantics and safe (explicit) bool conversion (although other than that, it is very similar in nature). This would change the code to look like this:std::optional> CCOMErrorHandler::PopError()
{
typedef std::tuple tuple_type;
std::optional error;
if(!m_lstErrors.empty()) {
error = *m_lstErrors.front();
m_lstError.pop_front();
}
return error;
}cppreference has an API reference for
std::optional. As for the complaint about template types, you can always wrap them in another namespace to help prevent pollution:
namespace mynamespace
{
namespace detail
{
typedef std::tuple error_type;
typedef std::optional optional_error;
}
detail::optional_error CCOMErrorHandler::PopError()
{
//...
}Code Snippets
std::optional<std::tuple<tstring, int, tstring>> CCOMErrorHandler::PopError()
{
typedef std::tuple<tstring, int, tstring> tuple_type;
std::optional<tuple_type> error;
if(!m_lstErrors.empty()) {
error = *m_lstErrors.front();
m_lstError.pop_front();
}
return error;
}namespace mynamespace
{
namespace detail
{
typedef std::tuple<tstring, int, tstring> error_type;
typedef std::optional<error_type> optional_error;
}
detail::optional_error CCOMErrorHandler::PopError()
{
//...
}Context
StackExchange Code Review Q#31777, answer score: 5
Revisions (0)
No revisions yet.