I don't have a lot of experience writing C++ and I'm struggling with an issue. The code below is kind of scraped together from snippets. I am writing a class and I want it to have an attribute map of string keys and function values:
std::map< std::string, std::function<bool(std::string)> > selection_filters;
I then want to add pairs as follows:
auto some_func = [] (std::string value) { return value == "some_val"; };
selection_filters["some_key"] = some_func;
//or
selection_filters.insert(std::make_pair("some_key", some_func));
Such that I can:
if ( selection_filters["some_key"]("function param") == true ) {
//etc..
}
This compiles, but throws an error at runtime:
terminating with uncaught exception of type std::__1::bad_function_call: std::exception
I suspect it may have something to do with a discrepancy between std::function<bool(std::string)> in the map definition, and the use of the lambda function [] (std::string value) { ... };
I would very much like to preserve the use of lambda functions and the possibility to access the functions through the subscript operators on the map (map['some_key'](..)) but my knowledge of C++ is not good enough to come up with a solution.
Can someone please point out the error I'm making (and why it is thrown; I want to learn) and provide suggestions for improvement?
See What causes std::bad_function_call?
Missing or empty function. Be sure to check that "some_key" exists in the map before you call the function,
if(selection_filters.find("some_key") != selection_filters.end())
or at least check that the function has a valid target:
if(selection_filters["some_key"])
When you use the [] operator on an std::map, it will insert a default constructed object (or zero) if it is not already in the map. This can (and will) cause lots of invalid entries for keys that you have not explicitly set.
Related
In go a common way to do error handling and still return a value is to use tuples.
I was wondering if doing the same in C++ using std::tie would be a good idea when exceptions are not applicable.
like
std::tie(errorcode, data) = loadData();
if(errorcode)
...//error handling
Are there any downsides to doing so (performance or otherwise)? I suppose with return value optimization it doesn't really make a difference but maybe I'm wrong.
One potential problematic case that I could see is the use in a cross-compiler API but that's not specific to this use.
The current way I do this is
errorcode = loadData(&data);
if(errorcode)
...//error handling
but that allows to pass in a value for data.
The errorcode itself is something that is already defined and that I can't change.
Edit: I'm using/have to use C++11
Sometimes output parameters are very handy. Suppose that loadData returns std::vector<T> and is called in a loop:
std::pair<ErrorCode, std::vector<T>> loadData();
for (...) {
ErrorCode errorcode;
std::vector<T> data;
std::tie(errorcode, data) = loadData();
}
In this case loadData will have to allocate memory on each iteration. However, if you pass data as the output parameter, previously allocated space can be reused:
ErrorCode loadData(std::vector<T>&);
std::vector<T> data;
for (...) {
ErrorCode errorcode = loadData(data);
}
If the above is of no concern, then you might want to take a look at expected<T, E>. It represents either
a value of type T, the expected value type; or
a value of type E, an error type used when an unexpected outcome occurred.
With expected, loadData() signature might look like:
expected<Data, ErrorCode> loadData();
C++11 implementation is available: https://github.com/TartanLlama/expected
There are multiple competing strategies for error handling. I will not go into it, as it is beyond the scope of the question, but error handling by return error codes is only one option. Consider alternatives like std::optional or exceptions, which are both common in C++, but not in Go.
If you have a function that is intended to return a Go-style error code plus value, then your std::tie solution is perfectly fine in C++11 or C+14, although in C++17, you would prefer structured bindings instead.
Are there any downsides to doing so (performance or otherwise)?
Yes. With tie, a copy or move of the returned values is required that would not be required if you avoid tie:
auto result = loadData();
if (std::get<0>(result))
...//error handling
Of course, if you would later copy or move the data somewhere else anyway, like in
data = std::move(std::get<1>(result));
then use tie because it is shorter.
I'm currently building a library that parses XML definitions for hardware configurations (obtained from the manufacturer).
I've mapped the XML types to c++ classes, and I'm making use of std::optional where ever there is an optional XML member when it is semantically correct for that piece of data to be missing.
I'm now trying to come up with a good error-handling strategy for my datatypes.
Sometimes, the XML may be missing some information that is marked as required by the schema, or a required element might not be found (which would be a different error to an element which is missing required data).
The basic idea for all the types follows this (example) class:
class TMyXmlType {
std::string name;
std::optional<int> factor;
std::optional<int> minFactor;
std::optional<int> maxFator;
public:
TMyXmlType(const xml_node & root){
if(root){ // Check if the element exists
name = root.value();
if(root.has_child("factor"){ factor = root.child("factor").value(); }
if(root.has_child("minFactor"){ factor = root.child("minFactor").value(); }
if(root.has_child("maxFator"){ factor = root.child("maxFator").value(); }
}else{
// What do I do here?
}
}
operator Json::Value() const {
if(/*object constructed correctly?*/){
Json::Value asJson;
asJson["name"] = name;
if(factor.has_value()){ asJson["factor"] = factor.value(); }
if(minFactor.has_value()){ asJson["minFactor"] = minFactor.value(); }
if(maxFator.has_value()){ asJson["maxFator"] = factor.maxFator(); }
return asJson;
}else{
// return error object?
}
}
}
So far, so good. The optional members are being taken care of.
However, root might be an empty node (the xml parsing library returns an empty node if it wasn't found.).
I basically want to return an error object instead of the value of the class (in my operator function) if one or more required XML nodes weren't found.
As far as I was able to find, for modern C++ you're supposed to throw an exception if the constructor can't construct the object correctly, however, if I throw an exception, my aggregate datatypes will have massive constructors with a bunch of try/catch blocks for each required data-member, which would make the codebase a pain to read and to maintain.
So now, the question is: What would be the cleanest way to have the operator return an error object instead of the class data if a required member is missing?
I don't need the constructor to explicitly fail, it currently also won't ever throw (as far as I know) and I really want error objects to give to the caller instead of return codes or bubbling exceptions.
Plain and simple, when you don't wan't an error to fire don't do anything fancy - eg. just do:
class TMyXmlType {
std::string name;
std::optional<int> factor;
std::optional<int> minFactor;
std::optional<int> maxFator;
public:
TMyXmlType(const xml_node & root){
if(root){ // Check if the element exists
name = root.value();
if(root.has_child("factor"){ factor = root.child("factor").value(); }
if(root.has_child("minFactor"){ factor = root.child("minFactor").value(); }
if(root.has_child("maxFator"){ factor = root.child("maxFator").value(); }
}else{
name = "NODE_ERROR";
}
}
}
That being said - reconsider your design - passing an invalid node to the constructor is probably an error you don't wan't to silence and should probably fire an exception !
(But catch the exception at a higher level - not for every construction - perhaps that is your underlying misconception)
Checking if a node is found for a search should be done at the level calling the search. Eg. the following code seems sensible to me:
const auto& node_found = searchNode(...);
const auto optXmlType = node_found ? std::make_optional<TMyXmlType>(node_found) : std::nullopt;
However, you might want to wrap that in a function.
I have a function that returns a custom class structure, but how should I handle the cases where I wish to inform the user that the function has failed, as in return false.
My function looks something like this:
Cell CSV::Find(std::string segment) {
Cell result;
// Search code here.
return result;
}
So when succesful, it returns the proper result, but how should I handle the case when it could fail?
I thought about adding a boolean method inside Cell to check what ever Cell.data is empty or not (Cell.IsEmpty()). But am I thinking this issue in a way too complicated way?
There are three general approaches:
Use exceptions. This is what's in Bathsheba's answer.
Return std::optional<Cell> (or some other type which may or may not hold an actual Cell).
Return bool, and add a Cell & parameter.
Which of these is best depends on how you intend this function to be used. If the primary use case is passing a valid segment, then by all means use exceptions.
If part of the design of this function is that it can be used to tell if a segment is valid, exceptions aren't appropriate, and my preferred choice would be std::optional<Cell>. This may not be available on your standard library implementation yet (it's a C++17 feature); if not, boost::optional<Cell> may be useful (as mentioned in Richard Hodges's answer).
In the comments, instead of std::optional<Cell>, user You suggested expected<Cell, error> (not standard C++, but proposed for a future standard, and implementable outside of the std namespace until then). This may be a good option to add some indication on why no Cell could be found for the segment parameter passed in, if there are multiple possible reasons.
The third option I include mainly for completeness. I do not recommend it. It's a popular and generally good pattern in other languages.
Is this function a query, which could validly not find the cell, or is it an imperative, where the cell is expected to be found?
If the former, return an optional (or nullable pointer to) the cell.
If the latter, throw an exception if not found.
Former:
boost::optional<Cell> CSV::Find(std::string segment) {
boost::optional<Cell> result;
// Search code here.
return result;
}
Latter:
as you have it.
And of course there is the c++17 variant-based approach:
#include <variant>
#include <string>
struct CellNotFound {};
struct Cell {};
using CellFindResult = std::variant<CellNotFound, Cell>;
CellFindResult Find(std::string segment) {
CellFindResult result { CellNotFound {} };
// Search code here.
return result;
}
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
void cellsAndStuff()
{
std::visit(overloaded
{
[&](CellNotFound)
{
// the not-found code
},
[&](Cell c)
{
// code on cell found
}
}, Find("foo"));
}
The C++ way of dealing with abject failures is to define an exception class of the form:
struct CSVException : std::exception{};
In your function you then throw one of those in the failure branch:
Cell CSV::Find(std::string segment) {
Cell result;
// Search code here.
if (fail) throw CSVException();
return result;
}
You then handle the fail case with a try catch block at the calling site.
If however the "fail" branch is normal behaviour (subjective indeed but only you can be the judge of normality), then do indeed imbue some kind of failure indicator inside Cell, or perhaps even change the return type to std::optional<Cell>.
If you can use C++17, another approach would be to use an std::optional type as your return value. That's a wrapper that may or may not contain a value. The caller can then check whether your function actually returned a value and handle the case where it didn't.
std::optional<Cell> CSV::Find(std::string segment) {
Cell result;
// Search code here.
return result;
}
void clientCode() {
auto cell = CSV::Find("foo");
if (cell)
// do stuff when found
else
// handle not found
}
A further option is using multiple return values:
std::pair<Cell, bool> CSV::Find(std::string segment) {
Cell result;
// Search code here.
return {result, found};
}
// ...
auto cell = CSV::Find("foo");
if (cell->second)
// do stuff with cell->first
The boolean flag says whether the requested Cell was found or not.
PROs
well known approach (e.g. std::map::insert);
quite direct: value and success indicator are return values of the function.
CONs
obscureness of first and second which requires to always remember the relative positions of values within the pairs. C++17 structured bindings / if statement with initializer partially resolve this issue:
if (auto [result, found] = CSV::Find("foo"); found)
// do stuff with `result`
possible loss of safety (the calling code has to check if there is a result value, before using it).
Details
Returning multiple values from functions in C++
C++ Error Handling - downside of using std::pair or std::tuple for returning error codes and function returns
For parsing, it is generally better to avoid std::string and instead use std::string_view; if C++17 is not available, minimally functional versions can be whipped up easily enough.
Furthermore, it is also important to track not only what was parsed but also the remainder.
There are two possibilities to track the remainder:
taking a mutable argument (by reference),
returning the remainder.
I personally prefer the latter, as in case of errors it guarantees that the caller has in its hands a unmodified value which is useful for error-reporting.
Then, you need to examine what potential errors can occur, and what recovery mechanisms you wish for. This will inform the design.
For example, if you wish to be able to parse ill-formed CSV documents, then it is reasonable that Cell be able to represent ill-formed CSV cells, in which case the interface is rather simple:
std::pair<Cell, std::string_view> consume_cell(std::string_view input) noexcept;
Where the function always advances and the Cell may contain either a proper cell, or an ill-formed one.
On the other hand, if you only wish to support well-formed CSV documents, then it is reasonable to signal errors via exceptions and that Cell only be able to hold actual cells:
std::pair<std::optional<Cell>, std::string_view> consume_cell(...);
And finally, you need to think about how to signal end of row conditions. It may a simple marker on Cell, though at this point I personally prefer to create an iterator as it presents a more natural interface since a row is a range of Cell.
The C++ interface for iterators is a bit clunky (as you need an "end", and the end is unknown before parsing), however I recommend sticking to it to be able to use the iterator with for loops. If you wish to depart from it, though, at least make it work easily with while, such as std::optional<Cell> cell; while ((cell = row.next())) { ... }.
I often use -1 as the invalid value type when returning from a function, where the input yields incorrect output. For instance, writing an indexing function where the index is out of bounds, instead of throwing an exception, -1 can be returned. But when writing a function that has negative values as possible return types, this technique does not work. What is the correct way to return an invalid type value in such instances?
The technique I use mostly is to set the return type to be of type *int, and return a Pointer to NULL. But, that requires all return values to be of a pointer type, which seems like an extra overhead to the function. Is there an accepted standard for returning values in such cases?
In newer C++, I'd suggest using std::optional<>; if you don't yet have it, boost::optional<>.
One option would be to let your function take a bool& as an output parameter used to indicate if the returned value is valid.
int myFunc(bool& valid); // sets 'valid' to true if result is usable, false otherwise
Users can then do
bool valid = false;
Int result = myFunc(valid);
if (!valid) {
// Handle error
}
// Use result
Not the most pretty solution, but it does the job.
Apart from the answer I provided above, there's a very clean, continuation-passing solution (given you're non-virtual):
template<typename Success, typename Failed>
void parse( const std::string& str, Success s, Failed f )
{
auto a = start_parse(str);
if( a.problem() )
return f(); // you _might_ have an error code here
s( finish_parse(str, a) );
}
Then you might customize by:
Success:
[&i] (int i_) { i = i_; }
out(i), where out(int& output_) returns the above lambda for output_
actual code doing something useful
function to continue with
Failed:
[&i]{ i = 0; }, `[&i]{ i = nullopt; }, or any other default value
[] { throw MyFavouriteException(); }
retry logic
std::terminate()
[]{} if you don't care (or if you're 100% sure it'll succeed)
It might look a little verbose, but IMHO:
it's trivial to read
any other schematics can be mimicked, even if there's no default c'tor
easy to change as well
'you don't pay for what you don't use', can surely be optimized away
every schematic is visible and apparent from code:
for default value, caller sets it, not callee or global
std::optional<> and default value are handled the same
for exception, caller knows better what to throw
for no action, you don't have to lookup the implementation to know this
for std::terminate(), well, you know what to expect
if you 'speak' CPS, you might actually continue and save an if / catch / etc.
The only issue I see is constructor initializer lists. Any thoughts on this?
I'm currently learning C++ and practicing my Knowledge by implementing an simple AddressBook Application. I started with an Entry class and an AddressBook class which implements a STL Map to access the entries by the last names of the persons. Now I arrived at the following code:
Entry AddressBook::get_by_last_name(string last_name){
if(this->addr_map.count(last_name) != 0){
//What can I do here?
} else {
return addr_map[last_name];
}
In Scripting Languages I would just return something like -1, Error Message(A List in Python) to indicate that the Function failed. I don't want throw an exception, because it's part of the application logic. The Calling Class should be able to react to the request by printing something on the console or opening a Message Box. Now I thought about implementing the Scripting Languae Approach in C++ by introducing some kind of an Invalid State to the Class Entry. But isn't that bad practice in C++? Could it be that my whole class design is just not appropriate? I appreciate any help. Please keep in mind that I'm still learning C++.
Some quick notes about your code:
if(this->addr_map.count(last_name) != 0){
//What can I do here?
You probably wanted it the other way:
if(this->addr_map.count(last_name) == 0){
//handle error
But your real problem lies here:
return addr_map[last_name];
Two things to note here:
The operator[] for map can do 2 things: If the element exists, it returns it; If the element doesn't exist, it creaets a new (key,value) pair with the specified key and value's default constructor. Probably not what you wanted. However, if your if statement from before would have been the right way, then the latter would never happen because we would knowthe key exists before hand.
In calling count() before, you effectively tell map to try and find the element. By calling operator[], you are telling map to find it again. So, you're doing twice the work to retrieve a single value.
A better (faster) way to do this involves iterators, and the find method:
YourMap::iterator it = addr_map.find(last_name); //find the element (once)
if (it == addr_map.end()) //element not found
{
//handle error
}
return *it.second; //return element
Now, back to the problem at hand. What to do if last_name is not found?
As other answers noted:
Simplest solution would be to return a pointer (NULL if not found)
Use boost::optional.
Simply return the YourMap::iterator but it seems that you are trying to "hide" the map from the user of AddressBook so that's probably a bad idea.
throw an exception. But wait, now you'll have to first check that calling this method is 'safe' (or handle the exception when appropriate). This check requires a boolean method like lastNameExists which would have to be called before calling get_by_last_name. Of course then we'er back to square 1. We're performing 2 find operations to retrieve a single value. It's safe, but if you're doing A LOT of calls to get_by_last_name then this is potentially a good place to optimize with a different solution (besides, arguably the exception is not very constructive: What's wrong with searching for something that isn't there, huh?).
Create a dummy member for Entryindicating that is not a real Entry but that is very poor design (unmanageable, counter intuitive, wasteful - you name it).
As you can see, the first 2 solutions are by far preferable.
One dead-simple option is to change the return type to Entry* (or const Entry*) and then return either the address of the Entry if found, or NULL if not.
If you use Boost, you could return a boost::optional<Entry>, in which case your success code would be the same, but on not-found you'd say return boost::none. This is fancier, but does about the same thing as using a pointer return type.
Throwing an exception is definitely the 'correct' C++ thing to do, based on your function return type.
You might want a function like this to help you, though:
bool AddressBook::lastNameExists(const string &last_name)
{
return addr_map.count(last_name) > 0;
}
Note that your current code returns the entry 'by value' so modifying the returned entry won't update the map. Not sure if this is by accident or design...
Other answers have given various approaches, most of them valid. I didn't see this one yet:
You could add a second parameter with a default value:
Entry AddressBook::get_by_last_name(string last_name, const Entry& default_value){
if(this->addr_map.count(last_name) == 0){
return default_value;
} else {
return addr_map[last_name];
}
In this particular instance, there might not be a sensible default value for a non-existing last name, but in many situations there is.
In C++ you have several ways of signalling that an issue happened in your function.
You can return a special value which the calling code will recognize as an invalid value. This can be a NULL pointer if the function should return a pointer, or a negative value if your function returns an index in an array, or, in the case of a custom class (e.g. your Entry class) you can define a special Entry::invalid value or something similar that can be detected by the calling function.
Your calling code could look like
if ( entryInstance->get_by_last_name("foobar") != Entry::invalid)
{
// here goes the code for the case where the name is valid
} else {
// here goes the code for the case where the name is invalid
}
On the other hand you can use the C++ exceptions mechanism and make your function throw an exception. For this youcan create your own exception class (or use one defined in the standard library, deriving from std::exception). Your function will throw the exception and your calling code will have to catch it with a try...catch statement.
try
{
entryInstance->get_by_last_name("foobar")
}
catch (Exception e)
{
// here goes the code for the case where the name is invalid
}
// here goes the code for the case where the name is valid
Apart from the fact that you could have more than one entry per surname.
Eliminate the getter, and you've solved the problem, or at least shifted it elsewhere.
Tell the AddressBook to display people with given surnames. If there aren't any it can do nothing.
AddressBookRenderer renderer;
AddressBook contacts;
contacts.renderSurnames("smith", renderer);
contacts.renderCompletions("sm", renderer);
//etc
You can do what std::map (and the other containers do).
You return an iterator from your search function.
If the search does not find a value that is useful return an iterator to end().
class AddressBook
{
typedef <Your Container Type> Container;
public:
typedef Container::iterator iterator;
iterator get_by_last_name(std::string const& lastName) {return addr_map.find[lastName];}
iterator end() {return addr_map.end();}
};
Your address book is a container like object.
Not finding an item in a search is likely to happen but it does not have enough context to incorporate error handling code (As the address book could be used from lots of places and each place would have different error handling ideas).
So you must move the test for not found state out of your address book.
just like "Python" we return a marker. In C++ this is usually an iterator to end() which the calling code can check and take the appropriate action.
AddressBook& ab = getAddressBookRef();
AddressBook::iterator find = ab.get_by_last_name("cpp_hobbyist");
if (find != ab.end())
{
Entity& person *find; // Here you have a reference to your entity.
// you can now manipulate as you want.
}
else
{
// Display appropriate error message
}