Related
I was coding with a beginner C++ group and we were creating a 'Car' class. Someone suggested 'tyre type' as a possible variable/attribute to the class as a boolean type. Another person then asked whether booleans should be directly answerable with a yes/no.
I was just wondering the same. How do you best manage a variable this and how do you later specify two options, such as winter/summer, for this variable?
Well, it depends.
Your goal is to write clear, readable, maintainable, and correct code. It's not so much that bool necessitates a yes vs. no answer as much as it is a question of whether or not using boolean (or any other type for that matter) helps you to meet these goals. If it makes your code clear, it's worth considering. If it makes things confusing, it's not a good idea.
For example, you may only have two types of tires, but consider a couple of things:
How do you know you won't add more later? You don't want to shoot yourself in the foot.
When writing / reading the code how do you remember that true is "summer" and false is "winter"? Will you have to maintain that info in your head / always look it up somewhere? Will it be easy to make a mistake? Will it confuse a reader who is unfamiliar with your code?
Think about those kinds of things. In your case, while using a boolean will certainly get the job done, I'd say it's a good use for an enum, even if you only have two values right now (or ever). E.g.:
enum TireType { WinterTire, SummerTire };
Now everything falls into place:
You can add new types in the future if you'd like, with no major issues.
A variable TireType t documents itself, we know just at a glance that t is a tire type.
There is much less of a chance of mistake when entering values: It'll be very hard to confuse WinterTire with SummerTire, whereas true and false discard all semantic meaning.
A boolean has two options, but those options are "true" or "false" (or, occasionally, "yes" and "no").
We do not generally represent other variables with two options as booleans.
If you have tyre types (of which there currently so happen to be two), I would suggest enums for this.
As always, there are exceptions. If your tyre types are "tyre with oil on it" and "tyre without oil on it", then you could use a boolean called tyreHasOilOnIt.
Really, it is up to you.
A boolean type is generally a value with precisely two values, one being truthy and the other falsy. This can to some degree be bent to other meanings. In your case when I saw discussion of tyre type I had no idea what the two values would mean untill reading the comments.
In my opinion when the value isn't self explanatory like this I would not use a boolean.
In your case, if the types of tyre are known at the time you write the program I would use an enum of some sort, and if they are not known just a plain string.
I would suggest don't use either enum or bool type for tyre type as a possible variable/attribute may change as you specified yes/no or Winter/Summer . Its better to use it as short int which values you can track or map with respect to yes,no,winter,summer . This will allow you to assign or change as per your need and class will never need a change.
Example :
Class car
{
// we will use tyre type to map enum
//type and other type if required
int tyreType;
};
enum tyre_type_t
{
//default value is considered 100
// since we can use previous
//value any other purpose.
WINTER = 100,
SUMMER
}
int main()
{
Car obj;
obj.tyreType = 1; // Yes
obj.tyreType = 0; // No
obj.tyreType = WINTER;
// Now we can assig enum.
// values //too.
return 0;
}
Happy Coding
Example :
Class car
{
// we will use tyre type to map enum
//type and other type if required
int tyreType;
};
enum tyre_type_t
{
//default value is considered 100
// since we can use previous
//value any other purpose.
WINTER = 100,
SUMMER
}
int main()
{
Car obj;
obj.tyreType = 1; // Yes
obj.tyreType = 0; // No
obj.tyreType = WINTER;
// Now we can assig enum.
// values //too.
return 0;
}
Happy Coding
currently I am doing the following:
enum TC_ID {
CMD01 = 'C'*'M'*'D'*'0'*'1',
CMD02 = 'C'*'M'*'D'*'0'*'2',
..
};
Which works, but is going to be quite effortfull for a whole lot of commands :D
So, I am looking for a Macro, or inline function or something else which multiplies all the chars of a char array/string with a fixed size, so that I don't have to type them in manually in my code.
Is something like this possible?
Some unnecessary but maybe interesting information:
Well, this looks kinda stupid, why am I doing this you might ask ;)
My goal is to use this enum in a switch statement, which in the end is used to execute telecommands for my project.
The size of my telecommands is always 5.
So I am calculating some kind of very simple hash value which will be used inside the switch statement:
char *id // contains the Telecommand as a string
TC_ID hash = static_cast<TC_ID>(id[0]*id[1]*id[2]*id[3]*id[4]);
switch (hash) {
case (CMD01):
// execute funtion..
break;
case (CMD02):
// do something else
break;
default:
// unknown command
}
I know that instead of a switch I could just use a lot of if else statements and strcmp, but I don't want to because it's ugly :D
EDIT: Also, using an appropriate hash function would be much better.
However, how can this be implemented in an enumeration, so that I can still use my switch statement for the commands?
I think what I want is basically some kind of hash table which I can generate at the start for all command words and then make a switch over all of them.. but just how?
EDIT2: My compiler version is C++98
EDIT3: Workaround solution in comment in answer post
This works (C++11):
constexpr int multChars(const char* s /*string*/, int t = 1 /*tally*/){
return *s ? multChars(s+1, t*(*s)) : t;
};
//--------------------------------------------------------
//test it on a template (won't compile unless N is evaluated at compile time)
#include <iostream>
template<int N>
void printN() { std::cout<<N<<'\n'; }
int main(){
printN<multChars("ab")>();
return 0;
}
The ascii code of 'a' is 97 and the ascii code of 'b' is 98.
This returns 9506 as expected.
I developed a generic "Unsigned" class, or really a class template Unsigned<size_t N> that models after the C (C++) built-in unsigneds using the amount of uint8_ts as a parameter. For example Unsigned<4> is identical to a uint32_t and Unsigned<32> would be identical to a uint256_t -- if it existed.
So far I have managed to follow most if not all of the semantics expected from a built-in unsigned -- in particular sizeof(Natural<N>)==N, (Natural<N>(-1) == "max_value_all_bits_1" == ~Natural<N>(0)), compatibility with abs(), sign(), div (using a custom div_t structure), ilogb() (exclusive to GCC it seems) and numeric_limits<>.
However I'm facing the issue that, since 1.- a class template is just a template so templated forms are unrelated, and 2.- the template non-typed parameter requires a "compile-time constant", which is way stricter than "a const", I'm essentially unable to create a Unsigned given an unknown N.
In other words, I can't have code like this:
...
( ... assuming all adequate headers are included ...)
using namespace std;
using lpp::Unsigned;
std::string str;
cout<< "Enter an arbitrarily long integer (end it with <ENTER>) :>";
getline(cin, str, '\n');
const int digits10 = log10(str.length()) + 1;
const int digits256 = (digits10 + 1) * ceil(log(10)/log(256)); // from "10×10^D = 256^T"
// at this point, I "should" be able to, semantically, do this:
Unsigned<digits256> num; // <-- THIS I CAN'T -- num would be guaranteed
// big enough to hold str's binary expression,
// no more space is needed
Unsigned::from_str(num, str); // somehow converts (essentially a base change algo)
// now I could do whatever I wanted with num "as if" a builtin.
std::string str_b3 = change_base(num, 3); // a generic implemented somehow
cout<< "The number above, in base 3, is: "<< str_b3<< endl;
...
(A/N -- This is part of the testsuite for Unsigned, which reads a "slightly large number" (I have tried up to 120 digits -- after setting N accordingly) and does things like expressing it in other bases, which in and of itself tests all arithmethic functions already.)
In looking for possible ways to bypass or otherwise alleviate this limitation, I have been running into some concepts that I'd like to try and explore, but I wouldn't like to spend too much effort into an alternative that is only going to make things more complicated or that would make the behaviour of the class(es) deviate too much.
The first thing I thought was that if I wasn't able to pick up a Unsigned<N> of my choice, I could at least pick up from a set of pre-selected values of N which would lead to the adequate constructor being called at runtime, but depending on a compile-time value:
???? GetMeAnUnsigned (size_t S) {
switch (S) {
case 0: { throw something(); } // we can't have a zero-size number, right?
case 1, 2, 3, 4: { return Unsigned<4>(); break; }
case 5, 6, 7, 8: { return Unsigned<8>(); break; }
case 9, 10, 11, 12, 13, 14, 15, 16: { return Unsigned<16>(); break; }
....
default: { return Unsigned<128>(); break; } // wow, a 1Kib number!
} // end switch
exit(1); // this point *shouldn't* be reachable!
} // end function
I personally like the approach. However I don't know what can I use to specify the return type. It doesn't actually "solve" the problem, it only degrades its severity by a certain degree. I'm sure doing the trick with the switch would work since the instantiations are from compile-time constant, it only changes which of them will take place.
The only viable help to declare the return type seems to be this new C++0(1?)X "decltype" construct which would allow me to obtain the adequate type, something like, if I understood the feature correctly:
decltype (Unsigned<N>) GetMeAnUnsigned (size_t S) {
.. do some choices that originate an N
return Unsigned<N>();
}
... or something like that. I haven't entered into C++?X beyond auto (for iterators) yet, so the first question would be: would features like decltype or auto help me to achieve what I want? (Runtime selection of the instantiation, even if limited)
For an alternative, I was thinking that if the problem was the relation between my classes then I could make them all a "kind-of" Base by deriving the template itself:
template <size_t N>
class Unsigned : private UnsignedCommon { ...
... but I left that approach in the backburner because, well, one doesn't do that (make all a "kind-of") with built-ins, plus for the cases where one does actually treat them as a common class it requires initializing statics, returning pointers and leave the client to destruct if I recall correctly. Second question then: did I do wrong in discarding this alternative too early?
In a nutshell, your problem is no different from that of the built-in integral types. Given a short, you can't store large integers in it. And you can't at runtime decide which type of integer to use, unless you use a switch or similar to choose between several predefined options (short, int, long, long long, for example. Or in your case, Unsigned<4>, Unsigned<8>, Unsigned<256>. The size cannot be computed dynamically at runtime, in any way.
You have to either define a dynamically sized type (similar to std::vector), where the size is not a template parameter, so that a single type can store any type of integer (and then accept the loss of efficiency that implies), or accept that the size must be chosen at compile-time, and the only option you have for handling "arbitrary" integers is to hardcode a set of predefined sizes and choose between them at runtime.
decltype won't solve your problem either. It is fairly similar to auto, it works entirely at compile-time, and just returns the type of an expression. (The type of 2+2 is int and the compiler knows this at compiletime, even though the value 4 is only computed at runtime)
The problem you are facing is quite common. Templates are resolved at compile time, while you need to change your behavior at runtime. As much as you might want to do that with the mythical one extra layer of indirection the problem won't go away: you cannot choose the return type of your function.
Since you need to perform the operations based on runtime information you must fall back to using dynamic polymorphism (instead of the static polymorphism that templates provide). That will imply using dynamic allocation inside the GetMeAnUnsigned method and possibly returning a pointer.
There are some tricks that you can play, like hiding the pointer inside a class that offers the public interface and delegates to an internal allocated object, in the same style as boost::any so that the user sees a single type even if the actual object is chosen at runtime. That will make the design harder, I am not sure how much more complex the code will be, but you will need to really think on what is the minimal interface that you must offer in the internal class hierarchy to fulfill the requirements of the external interface --this seems like a really interesting problem to tacke...
You can't directly do that. Each unsigned with a separate number has a separate type, and the compiler needs to know the return type of your method at compile time.
What you need to do is have an Unsigned_base base class, from which the Unsigned<t> items derive. You can then have your GetMeAnUnsigned method return a pointer to Unsigned_base. That could then be casted using something like dynamic_cast<Unsigned<8> >().
You might be better off having your function return a union of the possible unsigned<n> types, but that's only going to work if your type meets the requirements of being a union member.
EDIT: Here's an example:
struct UnsignedBase
{
virtual ~UnsignedBase() {}
};
template<std::size_t c>
class Unsigned : public UnsignedBase
{
//Implementation goes here.
};
std::auto_ptr<UnsignedBase> GiveMeAnUnsigned(std::size_t i)
{
std::auto_ptr<UnsignedBase> result;
switch(i)
{
case 42:
result.reset(new Unsigned<23>());
default:
result.reset(new Unsigned<2>());
};
return result;
}
It's a very common problem indeed, last time I saw it was with matrices (dimensions as template parameters and how to deal with runtime supplied value).
It's unfortunately an intractable problem.
The issue is not specific to C++ per se, it's specific to strong typing coupled with compile-time checking. For example Haskell could exhibit a similar behavior.
There are 2 ways to deal with this:
You use a switch not to create the type but actually to launch the full computation, ie main is almost empty and only serve to read the input value
You use boxing: you put the actual type in a generic container (either by hand-crafted class or boost::any or boost::variant) and then, when necessary, unbox the value for specific treatment.
I personally prefer the second approach.
The easier way to do this is to use a base class (interface):
struct UnsignedBase: boost::noncopyable
{
virtual ~UnsignedBase() {}
virtual UnsignedBase* clone() const = 0;
virtual size_t bytes() const = 0;
virtual void add(UnsignedBase const& rhs) = 0;
virtual void substract(UnsignedBase const& rhs) = 0;
};
Then you wrap this class in a simple manager to ease memory management for clients (you hide the fact that you rely on heap allocation + unique_ptr):
class UnsignedBox
{
public:
explicit UnsignedBox(std::string const& integer);
template <size_t N>
explicit UnsignedBox(Unsigned<N> const& integer);
size_t bytes() const { return mData->bytes(); }
void add(UnsignedBox const& rhs) { mData->add(rhs.mData); }
void substract(UnsignedBox const& rhs) { mData->substract(rhs.mData); }
private:
std::unique_ptr<UnsignedBase> mData;
};
Here, the virtual dispatch takes care of unboxing (somewhat), you can also unbox manually using a dynamic_cast (or static_cast if you know the number of digits):
void func(UnsignedBase* i)
{
if (Unsigned<2>* ptr = dynamic_cast< Unsigned<2> >(i))
{
}
else if (Unsigned<4>* ptr = dynamic_cast< Unsigned<4> >(i))
{
}
// ...
else
{
throw UnableToProceed(i);
}
}
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Inadvertent use of = instead of ==
C++ compilers let you know via warnings that you wrote,
if( a = b ) { //...
And that it might be a mistake that you certainly wanted to write:
if( a == b ) { //...
But is there a case where the warning should be ignored, because it's a good way to use this "feature"?
I don't see any code clarity reason possible, so is there a case where it’s useful?
Two possible reasons:
Assign & Check
The = operator (when not overriden) normally returns the value that it assigned. This is to allow statements such as a=b=c=3. In the context of your question, it also allows you to do something like this:
bool global;//a global variable
//a function
int foo(bool x){
//assign the value of x to global
//if x is equal to true, return 4
if (global=x)
return 4;
//otherwise return 3
return 3;
}
...which is equivalent to but shorter than:
bool global;//a global variable
//a function
int foo(bool x){
//assign the value of x to global
global=x;
//if x is equal to true, return 4
if (global==true)
return 4;
//otherwise return 3
return 3;
}
Also, it should be noted (as stated by Billy ONeal in a comment below) that this can also work when the left-hand argument of the = operator is actually a class with a conversion operator specified for a type which can be coerced (implicitly converted) to a bool. In other words, (a=b) will evaulate to true or false if a is of a type which can be coerced to a boolean value.
So the following is a similar situation to the above, except the left-hand argument to = is an object and not a bool:
#include <iostream>
using namespace std;
class Foo {
public:
operator bool (){ return true; }
Foo(){}
};
int main(){
Foo a;
Foo b;
if (a=b)
cout<<"true";
else
cout<<"false";
}
//output: true
Note: At the time of this writing, the code formatting above is bugged. My code (check the source) actually features proper indenting, shift operators and line spacing. The <'s are supposed to be <'s, and there aren't supposed to be enourmous gaps between each line.
Overridden = operator
Since C++ allows the overriding of operators, sometimes = will be overriden to do something other than what it does with primitive types. In these cases, the performing the = operation on an object could return a boolean (if that's how the = operator was overridden for that object type).
So the following code would perform the = operation on a with b as an argument. Then it would conditionally execute some code depending on the return value of that operation:
if (a=b){
//execute some code
}
Here, a would have to be an object and b would be of the correct type as defined by the overriding of the = operator for objects of a's type. To learn more about operator overriding, see this wikipedia article which includes C++ examples: Wikipedia article on operator overriding
while ( (line = readNextLine()) != EOF) {
processLine();
}
You could use to test if a function returned any error:
if (error_no = some_function(...)) {
// Handle error
}
Assuming that some_function returns the error code in case of an error. Or zero otherwise.
This is a consequence of basic feature of the C language:
The value of an assignment operation is the assigned value itself.
The fact that you can use that "return value" as the condition of an if() statement is incidental.
By the way, this is the same trick that allows this crazy conciseness:
void strcpy(char *s, char *t)
{
while( *s++ = *t++ );
}
Of course, the while exits when the nullchar in t is reached, but at the same time it is copied to the destination s string.
Whether it is a good idea, usually not, as it reduce code readability and is prone to errors.
Although the construct is perfectly legal syntax and your intent may truly be as shown below, don't leave the "!= 0" part out.
if( (a = b) != 0 ) {
...
}
The person looking at the code 6 months, 1 year, 5 years from now, at first glance, is simply going to believe the code contains a "classic bug" written by a junior programmer and will try to "fix" it. The construct above clearly indicates your intent and will be optimized out by the compiler. This would be especially embarrassing if you are that person.
Your other option is to heavily load it with comments. But the above is self-documenting code, which is better.
Lastly, my preference is to do this:
a = b;
if( a != 0 ) {
...
}
This is about a clear as the code can get. If there is a performance hit, it is virtually zero.
A common example where it is useful might be:
do {
...
} while (current = current->next);
I know that with this syntax you can avoid putting an extra line in your code, but I think it takes away some readability from the code.
This syntax is very useful for things like the one suggested by Steven Schlansker, but using it directly as a condition isn't a good idea.
This isn't actually a deliberate feature of C, but a consequence of two other features:
Assignment returns the assigned value
This is useful for performing multiple assignments, like a = b = 0, or loops like while ((n = getchar()) != EOF).
Numbers and pointers have truth values
C originally didn't have a bool type until the 1999 standard, so it used int to represent Boolean values. Backwards compatibility requires C and C++ to allow non-bool expressions in if, while, and for.
So, if a = b has a value and if is lenient about what values it accepts, then if (a = b) works. But I'd recommend using if ((a = b) != 0) instead to discourage anyone from "fixing" it.
You should explicitly write the checking statement in a better coding manner, avoiding the assign & check approach. Example:
if ((fp = fopen("filename.txt", "wt")) != NULL) {
// Do something with fp
}
void some( int b ) {
int a = 0;
if( a = b ) {
// or do something with a
// knowing that is not 0
}
// b remains the same
}
But is there a case where the warning
should be ignored because it's a good
way to use this "feature"? I don't see
any code clarity reason possible so is
there a case where its useful?
The warning can be suppressed by placing an extra parentheses around the assignment. That sort of clarifies the programmer's intent. Common cases I've seen that would match the (a = b) case directly would be something like:
if ( (a = expression_with_zero_for_failure) )
{
// do something with 'a' to avoid having to reevaluate
// 'expression_with_zero_for_failure' (might be a function call, e.g.)
}
else if ( (a = expression2_with_zero_for_failure) )
{
// do something with 'a' to avoid having to reevaluate
// 'expression2_with_zero_for_failure'
}
// etc.
As to whether writing this kind of code is useful enough to justify the common mistakes that beginners (and sometimes even professionals in their worst moments) encounter when using C++, it's difficult to say. It's a legacy inherited from C and Stroustrup and others contributing to the design of C++ might have gone a completely different, safer route had they not tried to make C++ backwards compatible with C as much as possible.
Personally I think it's not worth it. I work in a team and I've encountered this bug several times before. I would have been in favor of disallowing it (requiring parentheses or some other explicit syntax at least or else it's considered a build error) in exchange for lifting the burden of ever encountering these bugs.
while( (l = getline()) != EOF){
printf("%s\n", l);
}
This is of course the simplest example, and there are lots of times when this is useful. The primary thing to remember is that (a = true) returns true, just as (a = false) returns false.
Preamble
Note that this answer is about C++ (I started writing this answer before the tag "C" was added).
Still, after reading Jens Gustedt's comment, I realized it was not the first time I wrote this kind of answer. Truth is, this question is a duplicate of another, to which I gave the following answer:
Inadvertent use of = instead of ==
So, I'll shamelessly quote myself here to add an important information: if is not about comparison. It's about evaluation.
This difference is very important, because it means anything can be inside the parentheses of a if as long as it can be evaluated to a Boolean. And this is a good thing.
Now, limiting the language by forbidding =, where all other operators are authorized, is a dangerous exception for the language, an exception whose use would be far from certain, and whose drawbacks would be numerous indeed.
For those who are uneasy with the = typo, then there are solutions (see Alternatives below...).
About the valid uses of if(i = 0) [Quoted from myself]
The problem is that you're taking the problem upside down. The "if" notation is not about comparing two values like in some other languages.
The C/C++ if instruction waits for any expression that will evaluate to either a Boolean, or a null/non-null value. This expression can include two values comparison, and/or can be much more complex.
For example, you can have:
if(i >> 3)
{
std::cout << "i is less than 8" << std::endl
}
Which proves that, in C/C++, the if expression is not limited to == and =. Anything will do, as long as it can be evaluated as true or false (C++), or zero non-zero (C/C++).
About valid uses
Back to the non-quoted answer.
The following notation:
if(MyObject * p = findMyObject())
{
// uses p
}
enables the user to declare and then use p inside the if. It is a syntactic sugar... But an interesting one. For example, imagine the case of an XML DOM-like object whose type is unknown well until runtime, and you need to use RTTI:
void foo(Node * p_p)
{
if(BodyNode * p = dynamic_cast<BodyNode *>(p_p))
{
// this is a <body> node
}
else if(SpanNode * p = dynamic_cast<SpanNode *>(p_p))
{
// this is a <span> node
}
else if(DivNode * p = dynamic_cast<DivNode *>(p_p))
{
// this is a <div> node
}
// etc.
}
RTTI should not be abused, of course, but this is but one example of this syntactic sugar.
Another use would be to use what is called C++ variable injection. In Java, there is this cool keyword:
synchronized(p)
{
// Now, the Java code is synchronized using p as a mutex
}
In C++, you can do it, too. I don't have the exact code in mind (nor the exact Dr. Dobb's Journal's article where I discovered it), but this simple define should be enough for demonstration purposes:
#define synchronized(lock) \
if (auto_lock lock_##__LINE__(lock))
synchronized(p)
{
// Now, the C++ code is synchronized using p as a mutex
}
(Note that this macro is quite primitive, and should not be used as is in production code. The real macro uses a if and a for. See sources below for a more correct implementation).
This is the same way, mixing injection with if and for declaration, you can declare a primitive foreach macro (if you want an industrial-strength foreach, use Boost's).
About your typo problem
Your problem is a typo, and there are multiple ways to limit its frequency in your code. The most important one is to make sure the left-hand-side operand is constant.
For example, this code won't compile for multiple reasons:
if( NULL = b ) // won't compile because it is illegal
// to assign a value to r-values.
Or even better:
const T a ;
// etc.
if( a = b ) // Won't compile because it is illegal
// to modify a constant object
This is why in my code, const is one of the most used keyword you'll find. Unless I really want to modify a variable, it is declared const and thus, the compiler protects me from most errors, including the typo error that motivated you to write this question.
But is there a case where the warning should be ignored because it's a good way to use this "feature"? I don't see any code clarity reason possible so is there a case where its useful?
Conclusion
As shown in the examples above, there are multiple valid uses for the feature you used in your question.
My own code is a magnitude cleaner and clearer since I use the code injection enabled by this feature:
void foo()
{
// some code
LOCK(mutex)
{
// some code protected by a mutex
}
FOREACH(char c, MyVectorOfChar)
{
// using 'c'
}
}
... which makes the rare times I was confronted to this typo a negligible price to pay (and I can't remember the last time I wrote this type without being caught by the compiler).
Interesting sources
I finally found the articles I've had read on variable injection. Here we go!!!
FOR_EACH and LOCK (2003-11-01)
Exception Safety Analysis (2003-12-01)
Concurrent Access Control & C++ (2004-01-01)
Alternatives
If one fears being victim of the =/== typo, then perhaps using a macro could help:
#define EQUALS ==
#define ARE_EQUALS(lhs,rhs) (lhs == rhs)
int main(int argc, char* argv[])
{
int a = 25 ;
double b = 25 ;
if(a EQUALS b)
std::cout << "equals" << std::endl ;
else
std::cout << "NOT equals" << std::endl ;
if(ARE_EQUALS(a, b))
std::cout << "equals" << std::endl ;
else
std::cout << "NOT equals" << std::endl ;
return 0 ;
}
This way, one can protect oneself from the typo error, without needing a language limitation (that would cripple language), for a bug that happens rarely (i.e., almost never, as far as I remember it in my code).
There's an aspect of this that hasn't been mentioned: C doesn't prevent you from doing anything it doesn't have to. It doesn't prevent you from doing it because C's job is to give you enough rope to hang yourself by. To not think that it's smarter than you. And it's good at it.
Never!
The exceptions cited don't generate the compiler warning. In cases where the compiler generates the warning, it is never a good idea.
RegEx sample
RegEx r;
if(((r = new RegEx("\w*)).IsMatch()) {
// ... do something here
}
else if((r = new RegEx("\d*")).IsMatch()) {
// ... do something here
}
Assign a value test
int i = 0;
if((i = 1) == 1) {
// 1 is equal to i that was assigned to a int value 1
}
else {
// ?
}
My favourite is:
if (CComQIPtr<DerivedClassA> a = BaseClassPtr)
{
...
}
else if (CComQIPtr<DerivedClassB> b = BaseClassPtr)
{
...
}
In the following two versions of switch case, I am wondering which version is efficient.
1:
string* convertToString(int i)
{
switch(i)
{
case 1:
return new string("one");
case 2:
return new string("two");
case 3:
return new string("three");
.
.
default:
return new string("error");
}
}
2:
string* convertToString(int i)
{
string *intAsString;
switch(i)
{
case 1:
intAsString = new string("one");
break;
case 2:
intAsString = new string("two");
break;
case 3:
intAsString = new string("three");
break;
.
.
default:
intAsString = new string("error");
break;
}
return intAsString;
}
1: has multiple return statements will it cause compiler to generate extra code?
This is a premature optimization worry.
The former form is clearer and has fewer source lines, that is a compelling reason to chose it (in my opinion), of course.
You should (as usual) profile your program to determine if this function is even on the "hot list" for optimization. This will tell you if there is a performance penalty for using break.
As was pointed out in the comments, it's very possible that the main performance culprit of this code is the dynamically allocated strings. Generally, when implementing this kind of "integer to string" mapping function, you should return string constants.
Both are.
What you should really be concerned about is your use of pointers here. Is it necessary? Who will delete these strings? Isn't there a simpler alternative?
There should be no difference in the compiled code.
However:
You'll probably find returning the strings by value to be more efficient.
If there are a lot of strings consider prepopulating a vector with them (or declare a static array) and use i as the index in.
A switch statement is basically a series of if statements as generated machine instructions. One simple optimization strategy is to place the most frequent case first in the switch statement.
I also recommend the same solution as Sebastian but without the assert.
static const char *numberAsString[] = {
"Zero",
"One",
"Two",
"Three",
"Four",
"Five",
"Six",
};
const char *ConvertToString(int num) {
if (num < 1 || num >= (sizeof(numberAsString)/sizeof(char*)))
return "error";
return numberAsString[num];
}
You can never know how optimization will influence the code produced unless you compile with a specific compiler version, a specific set of settings and a specific code base.
C++ optimizing compilers may decide to turn your source code upside down to gain a specific optimization only available for compiler architecture so-and-so without you ever knowing it. A powerful optimizing compiler may e.g. find out that only 2 out of 10 cases are ever needed and will optimize away the whole switch-case-statement.
So my answer to your question is: Mu.
If you turn optimizing on, both functions will very likely generate equivalent code.
The compiler most probably will optimize both versions to the same code.
They will almost certainly both be compiled to an identical, highly-efficient branch table. Use whichever one you feel is clearer.
I would suggest something of the form:
void CScope::ToStr( int i, std::string& strOutput )
{
switch( i )
{
case 1:
strOutput = "Some text involving the number 1";
... etc etc
}
By returning a pointer to a string created on the heap, you risk memory leaks. Specifically regarding your question, I would suggest that the least number of return paths is more advisable than premature optimisation.
Consider keeping the strings as static constants:
static char const g_aaczNUMBER[][] =
{
{"Zero"}, { "One" }, ...
};
static char const g_aczERROR[] = { "Error" };
char* convertIntToString(int i) const {
return i<0 || 9<i ? g_aczERROR : g_aaczNUMBER[i];
}
You optimise[*] switch statements by doing as little work as possible in the switch (because it's uncertain whether the compiler will common up the duplication). If you insist on returning a string by pointer, and using a switch statement, I'd write this:
string *convertToString(int i) {
const char *str;
switch(i) {
case 1 : str = "one"; break;
// etc
default : str = "error"; break;
}
return new string(str);
}
But of course for this example I'd probably just use a lookup table:
const char *values[] = {"error", "one", ... };
string convertToString(unsigned int i) {
if (i >= sizeof(values)/sizeof(*values)) i = 0;
return values[i];
}
That said, I just answered a question about the static initialization order fiasco, so you don't in general want rules of thumb which demand globals. What you do has to depend on the context of the function.
[*] Where I mean the kind of rule-of-thumb optimisation that you do when writing portable code, or in your first version, in the hope of creating code that is clear to read and won't need too much real optimisation. Real optimisation involves real measurements.
There won't be any difference in efficiency here. Certainly none that will matter. The only benefit of going with option #2 is if you'll need to do some post-processing of the string that applies to all cases.
There should not be any measurable difference, return statements should not generate any machinery. They should put a pointer to the string object (allocated on the heap) on the stack of the callsite.
The funny part is you worry about efficieny of break then return but make a new string every time.
The answer is it's up to the compiler, but it should not matter either way. Avoiding the new string will if you call this all the time.
The switch can often be optimized so that it performs a jump instead of a bunch of if else, but if you look in the assembly source you'll generally be underwhelmed by how little the optimizer does.