Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with declaration of the primitive type without the initial value known (C++)?

In some cases it happens for me to declare a variable without knowing its value first like:

int a;
if (c1) {
  a = 1;
} else if (c2) {
  a = 2;
} else if (c3) {
  a = -3;
} 
do_something_with(a);

Is it the standard professional practice to assign some clearly wrong value like -1000 anyway (making potential bugs more reproducible) or it is preferred not to add the code that does nothing useful as long as there are no bugs? From one side, looks reasonable to remove randomness, from the other side, magical and even "clearly wrong" numbers somehow do not look attractive.

In many cases it is possible to declare when the value is first known, or use a ternary operator, but here we would need it nested so also rather clumsy.

Declaring inside the block would move the variable out of the scope prematurely.

Or would this case justify the usage of std::optional<int> a and assert(a) later, making sure we have the value?

EDIT: The bugs I am talking about would occur if suddenly all 3 conditions are false that should "absolutely never happen".

like image 955
Audrius Meškauskas Avatar asked Sep 16 '21 08:09

Audrius Meškauskas


People also ask

Where can you not declare a variable in a C++ program?

Where can you not declare a variable in a C++ program? b) Within the block of a void function. In c++ there are three abs (absolute value) functions.

How do you assign a value to a variable in C++?

type variableName = value; Where type is one of C++ types (such as int ), and variableName is the name of the variable (such as x or myName). The equal sign is used to assign values to the variable.

How do you add one to a variable in C++?

A program can increment by 1 the value of a variable called c using the increment operator, ++, rather than the expression c=c+1 or c+=1.

What are primitive data types in C language?

Primitive Data Types. The primitive data types in c language are the inbuilt data types provided by the c language itself. Thus, all c compilers provide support for these data types.

What are default values assigned to primitive data types in Java?

Default Values Assigned to Primitive Data Types in Java Data Type Size Byte 1 byte Short 2 bytes Int 4 bytes Long 8 bytes 4 more rows ...

When to initialize primitive data type variable in Java?

It is considered a best practice to initialize a primitive data type variable before using it in code.

How to declare integer data type in C?

Integer data type is used to declare a variable that can store numbers without a decimal. The keyword used to declare a variable of integer type is “int”. Thus, to declare integer data type following syntax should be followed: Float data type declares a variable that can store numbers containing a decimal number.


Video Answer


5 Answers

As far as I know the most popular and safest way is using inline lambda call. Note that the if should be exhaustive (I added SOME_DEFAULT_VALUE as a placeholder). I suppose that if you don't know what to put in final else block you should consider a few options:

  • using optional and putting none in the else,
  • throwing exception that describes the problem,
  • putting assert if logically this situation should never happen
const int a = [&] {
  if (c1) {
    return 1;
  } else if (c2) {
    return 2;
  } else if (c3) {
    return -3;
  } else {
    return SOME_DEFAULT_VALUE;
  }
}();
do_something_with(a);

In a situation when the initialization logic duplicates somewhere you can simply extract the lambda to a named function as other answers suggest

like image 194
bartop Avatar answered Nov 07 '22 07:11

bartop


In my opinion, the safest option, if you dont want this other value (its just useless), then it may lead to really subtle bug which may be hard to find. Therefore I would throw an expectation when any of the conditions is not met:

int get_init_value(bool c1, bool c2, bool c3) {
    if (c1) { return 1; }
    else if (c2) { return 2; }
    else if (c3) { return -3; }
    throw std::logic_error("noone of conditions to define value was met");
}

That way we avoid getting some weird values that want actually match our code, but they would compile anyways ( debugging it may take a lot of time). I consider it way better than just assigning it some clearly wrong value.

like image 29
Michał Turek Avatar answered Nov 07 '22 08:11

Michał Turek


Opinion based answer!

I know the example is a simplification of a real, more complex example, but IMHO it seems nowadays this kind of design issue emerge more often, and people sometimes kinda tend to over-complicate it.

Isn't it the whole purpose of a variable to hold some value? Thus isn't having a default value for this variable also a feasible thing?

So what exactly is wrong with:

int a = -1000; // or some other value meant to used for undefined
if (c1) {
  a = 1;
} else if (c2) {
  a = 2;
} else if (c3) {
  a = -3;
} 
do_something_with(a);

It is simple and readable... No lambdas, exceptions and other stuff making the code unnecessary complicated...

Or like:

int a;
if (c1) {
  a = 1;
} else if (c2) {
  a = 2;
} else if (c3) {
  a = -3;
} else {
  a = -1000;  // default for unkown state
}
do_something_with(a);

You could introduce a constant const int undefined = -1000; and use the constant.
Or an enum if c1, c2, c3 are states in some sort (which it most likely is)...
You could rearrange the code to eliminate the variable if it is not needed elsewhere.

if (c1) {
  do_something_with(1);
} else if (c2) {
  do_something_with(2);
} else if (c3) {
  do_something_with(-3);
} 
like image 27
user1810087 Avatar answered Nov 07 '22 07:11

user1810087


I would introduce a default value. I'm usually using MAX value of the type for this.

Shortest you can do this with the ternary operator like this:

#include <climits>

int a = c1 ? 1 : c2 ? 2 : c3 ? -3 : INT_MAX;

do_something_with(a);
like image 38
Attis Avatar answered Nov 07 '22 08:11

Attis


I understand your real code is much more complicated than the outline presented, but IMHO the main problem here is

should we do_something_with(a) at all if a is undefined,

rather than

what the initial value should be.

And the solution might be adding explicitly some status flag like a_is_defined to the actual parameter a instead of using magic constans.

int a = 0;
bool a_is_defined = false;

When you set them both according to c... conditions and pass them to do_something() you'll be able to make a clear distinction between a specific if(a_is_defined) {...} path and a default (error handling?) else {...}.

Or even provide separate routines to explicitly handle both paths one level earlier: if(a_is_defined) do_someting_with(a); else do_something_else();.

like image 37
CiaPan Avatar answered Nov 07 '22 06:11

CiaPan