While looking at the following results from codecov I noticed that the if statement at line 40 has 4 branches instead of 2 as I was expecting.
if (!m_helper->getCwd(cwd)) {
throw std::runtime_error("Couldn't get current working dir");
}
Has this anything to do with the exception?
How do I get full coverage of that statement with the unit tests?
You can find the project here: https://github.com/pamarcos/gencc/
Edit:
The code of getCwd is available here:
bool HelperImpl::getCwd(std::string& str)
{
if (getcwd(reinterpret_cast<char*>(m_buffer.data()), sizeof(m_buffer)) == nullptr) {
str.clear();
return false;
}
str = reinterpret_cast<char*>(m_buffer.data());
return true;
}
Related
I have a TADOConnection pointing to a MySQL 8.0 instance. The connection is tested and it works. Following this example on how to use prepared statement, I'm having an error and I have no idea why.
The following code works fine, it will return true from the very last statement. No errors, no warnings.
AnsiString sqlQuery = "SELECT e.name FROM employee e WHERE e.id = 1;";
if (!_query->Connection->Connected) {
try {
_query->Connection->Connected = true;
} catch (EADOError& e) {
return false;
}
}
_query->SQL->Clear();
_query->SQL->Add(sqlQuery);
_query->Prepared = true;
try {
_query->Active = true;
if (_query->RecordCount == 0) {
return false;
}
} catch (EADOError& e) {
return false;
}
return true;
However, the following code fails executing _query->SQL->Add(sqlQuery); with this error:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
AnsiString sqlQuery = "SELECT e.name FROM employee e WHERE e.id = :id;";
if (!_query->Connection->Connected) {
try {
_query->Connection->Connected = true;
} catch (EADOError& e) {
return false;
}
}
_query->SQL->Clear();
_query->SQL->Add(sqlQuery); // <---- EOleException here
_query->Parameters->ParamByName("id")->Value = id;
_query->Prepared = true;
try {
_query->Active = true;
if (_query->RecordCount == 0) {
return false;
}
} catch (EADOError& e) {
return false;
}
return true;
Everywhere I find examples, all of them use :paramName to specify parameters. What am I missing?
Update 1
I have tried changing the code like this :
_query->SQL->Clear();
TParameter * param = _query->Parameters->AddParameter();
param->Name = "id";
param->Value = 1;
_query->SQL->Add(sqlQuery); // <---- EOleException still here
Some forum post suggests to switch the Advanced Compiler option "Register Variables" to "None", but this is already the setting of my project, and the exception is still thrown.
Update 2
I can ignore the error, and everything gets executed just fine, however it fails whenever I perform a step-by-step execution. Of course, I can still put a breakpoint after, and jump right over the faulty line, but it's still annoying and does not explain why there is this error there in the first place.
The exception is on setting the SQL string - which tells you that it's wrong. As per #RogerCigol's comment, you should NOT have the ; at the end of your SQL string.
Kudos to Roger for that.
If you want to access parameters, you MUST set the SQL string first, it will be parsed to identify the parameters. The parameters will not exist until the string is parsed, or you manually create them (which is pointless as they would be recreated on parsing the string).
You can also access the parameters as an ordered index, and I have always been able to use ? as an anonymous parameter with MySQL.
I wounder if there is some construction convention for constructing method with multiple if's. Most of the time before you fire your method you have to check input arguments and other things, eg. is not nullptr, is > 0, is != -1 etc. Sometimes you cannot check this in one if and as a result you have something like this:
if(arg != nullptr)
{
if()
{
if()
{
if()
{
/*actual code here*/
}
else
{
}
}
else
{
}
}
else
{
/* other error message like "License check error: wrong key!" */
}
}
else
{
/* wrong input args! */
}
Good convention is that your line has less than 80 characters which gives us less space for actual code. Code is getting more and more unreadable.
You could return early in the case of issues, or throw an exception:
if(arg == nullptr) {
log("arg was null, not doing anything");
return;
}
//if the user forgot to make the toast, we can do it for them
if(forgotToMakeToast) {
makeToast();
}
if(ranOverDog) {
//we can't continue if the user ran over our dog, throw an exception
throw too_angry_exception;
}
//actual code
This makes your code structure more obvious by relating the error handling to the error checking by locality.
What I usually do is something like this:
if(arg == nullptr)
{
/* wrong input args! */
return;
}
if()
{
/* other error message like "License check error: wrong key!" */
return;
}
...
/*actual code here*/
Then you have all your error "ifs" and error handling in one place, and the actual function code at the end, nicely separated.
When you have too many sub-levels of if, while, for in a function, it is a sign that the function should be split into 2 or more separate functions. Depending on specific code it could look something like this:
public void MyClass::Run(arg)
{
if(arg != nullptr)
{
if()
{
RunActualCode()
}
else
{
/* other error message like "License check error: wrong key!" */
}
}
else
{
/* wrong input args! */
}
}
private void MyClass::RunActualCode(...)
{
if()
{
if()
{
/*actual code here*/
}
else
{
}
}
else
{
}
}
There are many recommendation about this, for example:
Rec 4.7 Do not have too complex functions.
Everyone that has ever had to take over code written by someone else
knows that complex code is hard to maintain. There are many ways in
which a function can be complex, such as the number of lines of code,
the number of parameters, or the number of possible paths through a
function. The number of possible paths through a function, which is
the result from the use of many control flow primitives, is the main
reason to why functions are complex. Therefore you should be aware of
the fact that heavy use of control flow primitives will make your code
more difficult to maintain.
http://www.tiobe.com/content/paperinfo/CodingStandards/hem/industrial/bookindex.htm
Limiting complexity during development
Your original construction could be written like this:
do
{
if(nullptr == arg) // Note: *negate* your original conditions!
{
/* wrong input args! */
break;
}
if(...)
{
/* other error message like "License check error: wrong key!" */
break;
}
if(...)
{
...
break;
}
if(...)
{
...
break;
}
/*actual code here*/
} while (0);
Advantages:
no nested ifs;
use break instead of goto to jump out of the whole block;
the logic is clearer, and more maintainable: if you want to add a check guard, just append one more if(...){...; break;};
Disadvantages:
do-while(0) looks a bit strange;
you should negate all your original conditions, e.g. if(cond) => if(!cond), which may affect the code clarity;
I recently come across the below piece of code in this Apache Axis tutorial example.
int main()
{
int status = AXIS2_SUCCESS;
axutil_env_t *env = NULL;
axutil_allocator_t *allocator = NULL;
env = create_environment();
status = build_and_serialize_om(env);
(status == AXIS2_FAILURE)
{
printf(" build AXIOM failed");
}
axutil_env_free(env);
0;
}
What i don't understand is the 0; at the end.
Is that return statement without the return keyword?
I tried the below piece of code to test this in Visual Studio.
int main()
{
0; // in the second run, replaced 0 with 28
}
Both programmes ran without any problems. But echo %ERRORLEVEL% at
windows command line returned 0 for both.
But the below piece of code
int add()
{
0;
}
causes
Error 1 error C4716: 'add' : must return a value
I understand that return value 0 is implicitly added for the main().
I don't have a problem including the return keyword at all, but I am
porting the Axis2/C Library to a C++ project. And there are many instances
where I encountered 0;
Why is the above syntax causing this undefined behavior?
In C++ return can be omitted only in main() , in functions that return void, and in constructors and destructors. In the former case main() returns automatically 0. In your case the statement 0; is a syntactically correct statement, evaluated as a no-op, so the compiler is basically ignoring it.
Where did you find that code? It seems like it's corrupted, perhaps due to formatting for showing it on a web page or something...?
The original code (from https://github.com/bnoordhuis/axis2-c/blob/master/axiom/test/util/axiom_util_test.c) is:
int main()
{
int status = AXIS2_SUCCESS;
axutil_env_t *env = NULL;
status = build_and_serialize_om(env);
if(status == AXIS2_FAILURE)
{
printf(" build AXIOM failed");
}
axutil_env_free(env);
return 0;
}
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
Let's say I want to call four functions consecutively, which operate on some object of mine. If any of them fails, I want to return FAILURE without calling the others, and I want to return SUCCESS iff all of them completed successfully.
Normally, I would do something like this:
if(function_zero(&myMutableObject) == SUCCESS)
{
return FAILURE;
}
if(function_one(&myMutableObject) == SUCCESS)
{
return FAILURE;
}
if(function_two(&myMutableObject) == SUCCESS)
{
return FAILURE;
}
if(function_three(&myMutableObject) == SUCCESS)
{
return FAILURE;
}
return SUCCESS;
Or, if I needed to do some cleanup:
if(function_zero(&myMutableObject) == SUCCESS)
{
status = FAILURE;
goto cleanup;
}
if(function_one(&myMutableObject) == SUCCESS)
{
status = FAILURE;
goto cleanup;
}
if(function_two(&myMutableObject) == SUCCESS)
{
status = FAILURE;
goto cleanup;
}
if(function_three(&myMutableObject) == SUCCESS)
{
status = FAILURE;
goto cleanup;
}
cleanup:
// necessary cleanup here
return status;
However, the project I am working on has some restrictions:
No goto, ever
No early return (one return per function)
Line length limit
(EDIT) No exceptions.
(EDIT) No templates.
This leads me to something like this:
if(function_zero(&myMutableObject) == SUCCESS)
{
if(function_one(&myMutableObject) == SUCCESS)
{
if(function_two(&myMutableObject) == SUCCESS)
{
status = function_three(&myMutableObject);
}
else
{
status = FAILURE;
}
}
else
{
status = FAILURE;
}
}
else
{
status = FAILURE;
}
return status;
Unfortunately, this pushes me up against the line length limit often.
My question to you is: Is there a simpler way of writing this?
Notes & Restrictions:
I must implement this logic within the code block implied here. I cannot create new functions, refactor or change the overall architecture.
(EDIT) In reality the functions have very different signatures.
Use exceptions and RAII. These are literally the problems they were invented to solve. Exceptions though are more of a system-wide feature, rather than something you can apply locally.
For the cleanup block, RAII is exactly the feature you need.
For the success/failure, we can use lambdas and variadics to chain them together implicitly.
Now we can simply write them as lambdas in the list.
status f() {
struct nested {
static template<typename F> status_t Check(F f) {
return f();
}
static template<typename F, typename... Chain> status_t Check(F f, Chain... chain) {
auto status = f();
return status != failure ? Check(chain...) : status;
}
};
return nested::Check(
[] { return function_zero(&myMutableObject); },
[] { return function_one(&myMutableObject); },
[] { return function_two(&myMutableObject); },
[] { return function_three(&myMutableObject); },
);
}
This becomes slightly more problematic if you need to capture the return value, but since it seems to be always an error code with out parameter, it should be fine if you simply declare the receiving variable in f(), then all the future lambdas can refer to it. It also does not require that every function has the same signature, or allocating various data structures.
Only call the tests if status is currently set to SUCCESS using an && operator. If it is set to FAILURE the && will fail immediately and the subsequent tests will not be executed.
status = SUCCESS
if (status == SUCCESS && function_zero(&myMutableObject) == FAILURE)
{
status = FAILURE;
}
if (status == SUCCESS && function_one(&myMutableObject) == FAILURE)
{
status = FAILURE;
}
if (status == SUCCESS && function_two(&myMutableObject) == FAILURE)
{
status = FAILURE;
}
if (status == SUCCESS && function_three(&myMutableObject) == FAILURE)
{
status = FAILURE;
}
return status;
As #Mooing Duck suggested, you could simply do it all in an else if chain:
status = SUCCESS
if (function_zero(&myMutableObject) == FAILURE)
{
status = FAILURE;
}
else if (function_one(&myMutableObject) == FAILURE)
{
status = FAILURE;
}
else if (function_two(&myMutableObject) == FAILURE)
{
status = FAILURE;
}
else if (function_three(&myMutableObject) == FAILURE)
{
status = FAILURE;
}
return status;
A pattern that I used several times when dealing with a long chain of C calls (typically WinAPIs) goes like this:
bool ret =
function_zero(&myMutableObject) == SUCCESS
&&
function_one(&myMutableObject) == SUCCESS
&&
function_two(&myMutableObject) == SUCCESS
&&
function_three(&myMutableObject) == SUCCESS;
if(!ret)
{
// cleanup
}
return ret?SUCCESS:FAILURE;
You may even leave the && at the end of each line, so that it looks more like a "normal" sequence of calls (although personally I like them better this way, it's clearer what's going on).
The && operator guarantees execution in the right order and only if the previous calls succeeded, and introduces the necessary sequence points (or however they are called in C++11) between the calls, so the order of evaluation of parameters between the various calls is well defined. Also, it has low enough priority not to require additional parentheses.
If you are not afraid of using COM-style macros, you can also encapsulate the == SUCCESS check in a macro, like
// in some header, maybe with a less abused name
#define OK(x) ((x) == SUCCESS)
bool ret =
OK(function_zero(&myMutableObject))
&&
OK(function_one(&myMutableObject))
&&
OK(function_two(&myMutableObject))
&&
OK(function_three(&myMutableObject));
// ...
Even better, if SUCCESS != 0 and FAILURE == 0 you can drop the OK() and == SUCCESS altogether and just use && to link the calls.
You say no exceptions, but I think you ought to know what you're giving up with that.
If you use RAII based cleanup and report errors as exceptions rather than codes, then you get code that looks like this:
function_zero(&myMutableObject);
function_one(&myMutableObject);
function_two(&myMutableObject);
function_three(&myMutableObject);
Here's a site that explains correct C++ exception handling and the benefits:
http://exceptionsafecode.com/
Some of the benefits are:
easier to read
easier to understand and maintain
wrong code looks wrong
easier to write
improved performance on the success path
'zero-cost' exceptions
compiler understands exceptions as a language feature, knows which path is the success path and which is the failure path
code size increase for exception tables is offset by elimination of error checking code
Furthermore, Herb Sutter has this to say on the subject of 'single exit' (the common name for your "No early return" rule):
In general, note that SE/SE is an obsolete idea and has always been
wrong. “Single entry,” or the idea that functions should always be
entered in one place (at their start) and not with goto jumps from the
caller’s code directly to random places inside the function body, was
and is an immensely valuable advance in computer science. It’s what
made libraries possible, because it meant you could package up a
function and reuse it and the function would always know its starting
state, where it begins, regardless of the calling code. “Single exit,”
on the other hand, got unfairly popular on the basis of optimization
(‘if there’s a single return the compiler can perform return value
optimization better’—see counterexample above) and symmetry (‘if
single entry is good, single exit must be good too’) but that is wrong
because the reasons don’t hold in reverse—allowing a caller to jump in
is bad because it’s not under the function’s control, but allowing the
function itself to return early when it knows it’s done is perfectly
fine and fully under the function’s control.
http://herbsutter.com/category/c/gotw/page/4/
You should try to get the rules updated, even if that's only possible for new projects.
You could store the function pointers in a containers of std::function (as long as they have the same signature as in the example):
std::vector<std::function<error_code (myobject&)> functions { func1, func2, func3, func4 };
error_code status = SUCCESS;
for (const auto& f : functions) {
if (f(myobject) == ERROR) {
clean_up();
status = ERROR;
break;
}
}
return status;
This could work:
bool success = true;
success = success && function_zero(&myMutableObject) != FAILURE;
success = success && function_one(&myMutableObject) != FAILURE;
success = success && function_two(&myMutableObject) != FAILURE;
success = success && function_three(&myMutableObject) != FAILURE;
return success ? SUCCESS : FAILURE;
return can be replaced to:
int status = SUCCESS;
if( !success ) status = FAILURE;
return status;
if in your company conditional operator is prohibited as well.
You might write a simple local functor:
bool fn0(int&) { return false; }
bool fn1(int&) { return false; }
bool fn2(int&) { return false; }
int main() {
struct Test {
const bool result;
typedef bool (*function)(int&);
Test(function f, int& value)
: result(f(value))
{};
operator bool () const { return result; }
};
int value;
return Test(fn0, value)
&& Test(fn1, value)
&& Test(fn2, value);
}
Back again with CacheScript, this time an easier question.
Here is the problem code:
while (open.hasNext() == true) {
String code = open.nextLine();
if (code.equals("CacheScript")) {
JOptionPane.showMessageDialog(this, "Package Successfully Loaded.");
txtBar.setText("Cache Script 2014");
}
if (code.equals("cache.color.orange")) {
map.setBackground(Color.orange);
}
}
For some reason, when I run this, the scanner (open) does not follow through... How can I fix the while code so each line can be tested to see if it equals one of the commands?
Try this;
while (open.hasNext() == true) {
if (code.equals("CacheScript")) {
JOptionPane.showMessageDialog(this, "Package Successfully Loaded.");
txtBar.setText("Cache Script 2014");
}
if (code.equals("cache.color.orange")) {
map.setBackground(Color.orange);
}
String code = open.nextLine();
continue;
}