C/C++ Syntax - Separating statements with , instead of ; legal? - c++

I just ran into this piece of code that does this :
delete a, a = 0;
It compiles and runs just fine. But isn't this supposed to be :
delete a;
a = 0;
Why is separating statements using , allowed in this case ?
Thanks :)

In C and C++, most "statements" are actually expressions. The semicolon added to an expression makes it into a statement. Alternatively, it is allowed (but almost always bad style) to separate side-effectful expressions with the comma operator: the left-hand-side expression is evaluated for its side-effects (and its value is discarded), and the right-hand-side expression is evaluated for its value.

This is the comma-operator. It evaluates both it's arguments and returns the second one.

This is the comma operator. It can be used to separate expressions, but not declarations.

That is comma operator. MSDN article is here. And have a look at this question to understand how it works.

While it is possible to write code like that, it may be somewhat weird. A slightly more realistic usecase would be if you have a struct T as follows:
struct T {
bool check() const;
void fix();
};
Now you want to iterate through everything in the struct and run check on it, and then call fix if check returns false. The simple way to do this would be
for (list<T>::iterator it = mylist.begin(); it < mylist.end(); ++it)
if (!it->check())
it->fix();
Let's pretend you want to write it in as short a way as possible. fix() returning void means you can't just put it in the condition. However, using the comma operator you can get around this:
for (auto it = mylist.begin(); it != mylist.end() && (it->check() || (it->fix(), true)); ++it);
I wouldn't use it without a particularly good reason, but it does allow you to call any function from a condition, which can be convenient.

Related

short form of if (private case) c++ [duplicate]

Node is a very simple class with a just a constructor and a few variables: a "name" (actually just a char) and two child Node pointers called "left" and "right".
I was just starting to write some code that needs to drop to the left-most node, and I was quite pleased when I came up with this:
Node *current = this->root;
while (true) (current->left != nullptr) ? current = current->left : break;
Seems simple enough: in an infinite loop, check to see if current has a left child, if so, set current to that left child, if not, break out of the loop. It's a cool little one-liner, not too unreadable. (And I commented it!)
Well, my compiler doesn't like it:
iterator.cpp:20:70: error: expected expression
while (true) (current->left != nullptr) ? current = current->left : break;
^
1 error generated.
Also, just throwing some braces into the while loop and moving the ternary operator to it's own line didn't help (unsurprisingly). I had to turn it into an if/else for the compiler to accept it.
Can someone explain how it's interpreting the one-liner and why it objects?
The ternary conditional operator is an operator that combines multiple expressions into a larger expression. break is a statement and not an expression, so it can't be used inside a ternary conditional expression.
You could, though, rewrite your code like this:
while (current->left != nullptr) current = current->left;
Hope this helps!
Why can't I use a “break” statement inside a ternary conditional statement in C++?
Because the ternary operator isn't a statement at all, it's an operator, and it is composed of expressions, not statements. break is a statement, not an expression.

Conditional Operator: How much flexibility?

I would like to perform the following:
if(x == true)
{
// do this on behalf of x
// do this on behalf of x
// do this on behalf of x
}
Using a conditional operator, is this correct?
x == true ? { /*do a*/, /*do b*/, /*do c*/ } : y == true ? ... ;
Is this malformed?
I am not nesting more than one level with a conditional operator.
The expressions I intend to use are highly terse and simple making a conditional operator, in my opinion, worth using.
P.S. I am not asking A. Which I should use? B. Which is better C. Which is more appropriate
P.S. I am asking how to convert an if-else statement to a ternary conditional operator.
Any advice given on this question regarding coding standards etc. are simply undesired.
Don't compare booleans to true and false. There's no point because they're true or false already! Just write
if (x)
{
// do this on behalf of x
// do this on behalf of x
// do this on behalf of x
}
Your second example doesn't compile because you use { and }. But this might
x ? ( /*do a*/, /*do b*/, /*do c*/ ) : y ? ... ;
but it does depend on what /*do a*/ etc are.
Using comma operator to string different expressions together is within the rules of the language, but it makes the code harder to read (because you have to spot the comma, which isn't always easy, especially if the expression isn't really simple.
The other factor is of course that you can ONLY do this for if (x) ... else if(y) ... type conditionals state.
Sometimes, it seems like people prefer "short code" from "readable code", which is of course great if you are in a competition of "who can write this in the fewest lines", but for everything else, particularly code that "on show" or shared with colleagues that also need to understand it - once a software project gets sufficiently large, it usually becomes hard to understand how the code works WITHOUT obfuscation that makes the code harder to read. I don't really see any benefit in using conditional statements in the way your second example described. It is possible that the example is bad, but generally, I'd say "don't do that".
Of course it works (with C++11). I have not tried a solution but following Herb Sutters way you can use ether a function call or a lambda which is immediately executed:
cond ?
[&]{
int i = some_default_value;
if(someConditionIstrue)
{
Do some operations ancalculate the value of i;
i = some calculated value;
}
return i;
} ()
:
somefun() ;
I have not tried to compile it but here you have an result whih is either computed with an lambda or an normal function.

C++ Deleting a specfic value in a vector without knowing location

if (find(visitable.begin(), visitable.end(), ourstack.returnTop())) { ... }
I want to determine whether the top character in stack ourstack can be found in the vector visitable. If yes, I want this character to be deleted from visitable.
How would I code that? I know vectors use erase, but that requires the specific location of that character (which I don't know).
This is for my maze-path-finding assignment.
Also, my returnTop is giving me an error: class "std.stack<char..." has no member returnTop. I declared #include in the top of my program. What's happening here?
Thanks in advance!
If you are using find, then you already know the location of the character. find returns an iterator to the position where the character is found, or to the value used as end if it cannot find it.
vector<?>::const_iterator iter =
find(visitable.begin(), visitable.end(), ourstack.top());
if( iter != visitable.end() )
{
visitable.erase( iter );
}
As for stack, the function you are looking for is top(). The standard C++ library does not use camelCased identifiers, that looks more like a Java or C# thing.
Just like this:
// Note assume C++0x notation for simplicity since I don't know the type of the template
auto character = ourstack.top();
auto iter = std::find(visitable.begin(), visitable.end(), character);
if (iter != visitable.end())
visitable.erase(iter);
returnTop does not exist in the stack class, but top does.
Alternatively if you want some generic (and rather flamboyant way) of doing it:
// Assume type of vector and stack are the same
template <class T>
void TryRemoveCharacter(std::vector<T>& visitable, const std::stack<T>& ourStack)
{
// Note, could have passed a ref to the character directly, which IMHO makes more sense
const T& ourChar = ourStack.top();
visitable.erase(std::remove_if(visitable.begin(), visitable.end(), [&ourChar](const T& character)
{
// Note, this will not work http://www.cplusplus.com/reference/algorithm/find/
// says that std::find uses the operator== for comparisons but I doubt that
// as compilers typically do not generate equal comparison operator.
// See http://stackoverflow.com/questions/217911/why-dont-c-compilers-define-operator-and-operator
// It's best to either overload the operator== to do a true comparison or
// add a comparison method and invoke it here.
return ourChar == character;
}));
}
Note: this alternative way may not be a good idea for an assignment as your teacher will probably find suspicious that you introduce advanced C++ features (C++0x) all of a sudden.
However for intellectual curiosity it could work ;)
Here's how you may use it:
TryRemoveCharacter(visitable, ourstack);

Is this use of the "," operator considered bad form?

I have made a list class as a means of replacing variadic functions in my program used for initializing objects that need to contain a changing list of elements. The list class has a usage syntax that I really like. However I haven't seen it used before, so I was wondering if I shouldn't use it just because of that fact? A basic implementation of the list class looks like this...
#include <list>
#include <iostream>
template<typename T>
struct list
{
std::list<T> items;
list(const list&ref):items(ref.items){}
list(){}
list(T var){items.push_back(var);}
list& operator,(list add_){
items.insert(items.end(),add_.items.begin(), add_.items.end());
return *this;
}
list& operator=(list add_){
items.clear();
items.insert(items.end(),add_.items.begin(), add_.items.end());
return *this;
}
list& operator+=(list add_){
items.insert(items.end(),add_.items.begin(), add_.items.end());
return *this;
}
};
This allows me to have use this in code like so...
struct music{
//...
};
struct music_playlist{
list<music> queue;
//...
};
int main (int argc, const char * argv[])
{
music_playlist playlist;
music song1;
music song2;
music song3;
music song4;
playlist.queue = song1,song2; // The queue now contains song1 and song2
playlist.queue+= song1,song3,song4; //The queue now contains two song1s and song2-4
playlist.queue = song2; //the queue now only contains song2
return 0;
}
I really think that the syntax is much nicer than it would of been if I had just exposed a regular stl container, and even nicer (and typesafe) than variadic functions. However, since I have not seen this syntax used, I am curious about whether I should avoid it, because above all the code should be easily understood by other programmers?
EDIT:
In joint with this question, I have posted this question more targeted at solutions to the actual problem.
Why not overload the << operator as QList does? Then use it like:
playlist.queue << song1 << song2; // The queue now contains song1 and song2
playlist.queue << song1 << song3 << song4; //The queue now contains two song1s and song2-4
I agree that your syntax looks nice as you have written it.
My main difficulty with the code is that I would expect the following to be the same
playlist.queue = song1,song2;
playlist.queue = (song1,song2); //more of c-style, as #Iuser notes.
whereas in fact they are completely different.
This is dangerous because its too easy to introduce usage bugs into the code.
If someone likes to use parenthesis to add extra emphasis to groupings (not uncommon) then the comma could become a real pain. For example,
//lets combine differnt playlists
new_playlist.queue = song1 //the first playlist
,(song3,song4) //the second playlist //opps, I didn't add song 3!
, song5; //the third
or
new_playlist.queue = (old_playlist.queue, song6); //opps, I edited my old playlist too!
Incidently, have you come across boost.assign: http://www.boost.org/doc/libs/1_47_0/libs/assign/doc/index.html
Has the precedence changed recently?
playlist.queue = song1,song2;
This should parse as:
(playlist.queue = song1) , song2;
Your ',' and '+=' are the same!
It would be a better semantic match if your comma operator were to create a temporary list, insert the left and right items and return the temporary. Then you could write it like this;
playlist.queue = (song1,song2);
with explicit parens. That would give C-programmers a fighting chance at being able to read the code.
A bit of a problem is that if the compiler cannot choose your overloaded operator comma, it can fall back on using the built-in operator.
In contrast, with Boost.Assign mixing up types produces a compilation error.
#include <boost/assign.hpp>
int main()
{
int one = 1;
const char* two = "2";
list<int> li;
li = one, two;
using namespace boost::assign;
std::list<int> li2;
li2 += one, two;
}
This is probably something that belongs over on Programmers, but here's my two cents.
If you're talking about code that has a fairly narrow context, where users will use it in a couple of places and that's all, then overloading the , operator is probably OK. If you're building a domain-specific language that is used in a particular domain and nowhere else, it's probably fine.
The issue comes when you're overloading it for something that you expect the user to use with some frequency.
Overloading , means that the reader needs to completely reinterpret how they read your code. They can't just look at an expression and instantly know what it does. You're messing with some of the most basic assumptions that C++ programmers make when it comes to scanning code.
Do that at your own peril.
I am curious about whether I should avoid it, because above all the
code should be easily understood by other programmers
If the goal is to make your code easy for other C++ programmers to understand, overriding operators to give them a meaning that's very different from that of standard C++ is not a good start. Readers shouldn't have to a) understand how you've implemented your container and b) recalibrate their understanding of standard operators just to be able to make sense of your code.
I can appreciate the Boost precedent for this sort of thing. If you're pretty sure that most of the people who will read your code will also be familiar with Boost Assign, your own override of operator, might be pretty reasonable. Still, I'd suggest following #badzeppelin's suggestion to use operator<< instead, just as iostreams does. Every C++ developer can be counted on to have run into code like:
cout << "Hello world!"`
and your append operation is very similar to writing to a stream.
It's bad on so many levels...
You're overriding list and shadowingstd::list. A big no-no. If you want your own list class - make it be with a different name, don't shadow the standard library.
Using , in such way is not readable. The return value of the operator is the right operand. Even if your code works, for an external reader it won't be obvious why, and it's a bad thing. Code should be readable, not nice.
There is nothing bad about using comma operator , using specifically. Any operator leaves bad taste, if exploited. In your code, I don't see any reasonable problem. Only one suggestion, I would like to give is:
list& operator,(list &add_){ // <--- pass by reference to avoid copies
*this += add_; // <--- reuse operator +=
return *this;
}
This way, you have to always edit just operator +=, if you want any change in logic. Note that, my answer is in the perspective of readability and code maintenance in general. I will not raise concern about business logic you use.

Using comparison operators outside of conditionals

For example
int f(int a) {
...
return a > 10;
}
is that considered acceptable (not legal, I mean is it ``good code''), or should it always be in a conditional, like this
int f(int a) {
...
if (a > 10)
return 1;
else
return 0;
}
It would be acceptable - if your return type was bool.
This is absolutely acceptable! In fact, Joel mentioned this on the latest stackoverflow podcast. He said it was the one thing he's had to show almost every programmer that starts at Fog Creek.
return a > 10 ? 1 : 0;
... makes more sense because you're returning an int, not a bool.
The first case is perfectly good, far better than the second, IMHO. As a matter of readability, I personally would do
return (a > 10);
but that is a minor nit, and not one everyone would agree on.
I don't see anything wrong with it. If anything it's more concise and I think most developers with moderate experience would prefer it.
The first is much preferable to me, since it is more concise. (And it avoids multiple returns:)
I'd rather write bool f(int); and the first form as bool is the boolean type in C++. If I really need to return an int, I'd write something like
int f(int) {
...
const int res = (i>42) ? 1 : 0;
return res;
}
I'd never understood why people write
if (expr == true)
mybool = true ;
else
mybool = false;
instead of the plain
mybool = expr;
Boolean algebra is a tool that any developer should be able to handle instinctively
Moreover, I'd rather define a named temporary as some debuggers don't handle function return values very well.
I think its perfectly acceptable, provided that you ensure that you make an extra effort to maintain readability. Like I would make sure that the method name is very unambiguous and you use good variable names.
The second alternative that you provided I think is almost worse because it involves a branch statement and multiple return statements and these things increase the complexity of the method while themselves reducing its readability.
Not only is that syntax 100% acceptable, you should also feel free to use boolean expressions outside of if statements, i.e. int x = i && ( j || k ); (or returning values like that).
I think part of it has to do with the style and culture of the language. The first example you have written is what would be expected from an experienced C programmer. They would much rather strangle themselves than put in an unnecessary block of statements.
I think it is perfectly acceptable when the language allows it and the usage is part of the paradigm of that language
I just tried three different variants with GCC:
int one(int x) { return (x > 42) ? 1 : 0; }
int two(int x) { return x > 42; }
int thr(int x) { if (x > 42) return 1; else return 0; }
As soon as you enable some optimization, the generated code for all of them is the same. So you should use the variant that is easiest to read.
I'll typically do the former over the latter.