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 last month.
Improve this question
while I was writing some code, I found out there are two types of convention(or coding style) in terms of checking nullptr, when series of objects should be non-null.
Here how it goes :
Style 1
if (auto parent = ParentSpawner())
{
if (auto child = parent->ChildSpawner())
{
if (auto grandChild = child->GrandChildSpawner())
{
// Do something...
grandChild->DoSomething();
}
}
}
Style 2
auto parent = ParentSpawner();
if (nullptr == parent)
return;
auto child = parent->ChildSpawner();
if (nullptr == child)
return;
auto grandChild = child->GrandChildSpawner();
if (nullptr == grandChild)
return;
// Do something...
grandChild->DoSomething();
Which one should I prefer?
Plus, in Style 1, is there any overhead due to implicit casting inside of if statement? (from nullptr->bool)
(+ I found similar question in stackoverflow)
Regarding the implicit conversion, there shall be no overhead as this will be checked compile time, see cpp reference on implicit conversion
An expression e is said to be implicitly convertible to T2 if and only if T2 can be copy-initialized from e, that is the declaration T2 t = e; is well-formed (can be compiled), for some invented temporary t.
As for your second question regarding style. My suggestiong is purely a preference and will not be objective at all, neither based on any performance related facts.
Nested If Style 1
I would personnally prefer having this style if there is a clear dependence between the nested statements, it does make sense in your example, so I would go with Style 1.
Multiple point of exit Style 2
I usually go with that style when the various checks are not related to each other and cannot be combined in the same if. That doesn't happen too often.
Related
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 1 year ago.
This post was edited and submitted for review 7 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
for (auto& i : just_a_vec )
Or an iterator for loop.
for (std::vector<std::string>::iterator it = just_a_vec.begin(); it < just_a_vec.end(); it++)
Iterators predate range-based for loops, so they used to be the only of these two alternatives available. Nowadays, range-based for has mostly replaced iterators when dealing with a simple loop.
However, iterators can be used in various other contexts as well. For example, you can do std::sort(v.begin(), std::next(v.begin(), 5)) to sort the first five elements of a vector while leaving the rest of it alone.
Going back to iterating over a whole container:
If you can accomplish what you want with a range-based for, then it leads to more legible code, so they are preferable by default.
If you need iterators for some reason, such as using an algorithm that requires them, or because you need to jump ahead or back while iterating, then use those instead.
Also: In the later case, you can/should still use auto when declaring the iterator:
for(auto it = just_a_vec.begin(); it < just_a_vec.end(); it++) {
}
Edit: as asked: here's a simple, if a bit contrived, example where an iterator-based loop can still be useful:
// adds all values in the vector, but skips over twos values when encountering a 0
// e.g.: {1,2,0,4,5,2} => 5
int my_weird_accum(const std::vector<int>& data) {
int result = 0;
for(auto it = data.begin(); it != data.end(); ++it) {
auto v = *it;
result += v;
if(v == 0) {
// skip over the next two
assert(std::distance(it, data.end()) > 2);
std::advance(it, 2);
}
}
return 0;
}
Quick personal answer: Its somewhat sylistic and based on what version of c++ you are using. I typically prefer range based, but there are certainly moments iterators shine as well. Add both to your toolchest. For further reading.
Here is a list of other SO answers that get more into the performance and use cases.
What's the difference between iterator syntax in range-based loops for STL containers
Is the ranged based for loop beneficial to performance?
range based for loop vs regular iterator for loop
For further information. Google
Range vs iterator loop c++
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
How can I translate a loop like the below one to C style?
for (auto element : vector) {
Do_Somethin();
}
You'd start with converting it to a non-ranged-based for loop.
{
auto&& range = Chains;
using std::begin; using std::end; // possibly cbegin/cend
auto it = begin(range); // possibly cbegin
auto end = end(range); // possibly cend
for(; it!=end; ++it) {
auto block = *it;
// body of loop
}
}
then you tease apart each piece.
Start by deducing what the auto variables are. Guess if you have to, then do a static_assert( std::is_same_v< decltype(begin), your_guess > ); to confirm. Once you have confirmed, replace. DO NOT guess and swap in the type and assume "it compiles, I got it right"; that can lead to subtle bugs.
Then replace begin and end with an equivalent expression. You'll have to do some research (it could be raw pointers into arrays, or it could be .begin methods, or it could be a free begin function in the namespace of the range expression).
What happens next depends on what your iterators are here. Are they plain pointers? If so, the problem is probably pretty easy. If not, you have more work to do.
Finally, remove all references, and then tidy up.
Ideally you'd want to do each of these steps as a git commit with unit tests confirming no change of behavior. You appear not to be qualified to make these changes without such testing. That is ok, and the unit testing will have value.
Going the other way, there are C++ to C translators. They will generate unreadable and unmaintainable code in practice.
But the output can be compiled by a C compiler.
Yes, you can always exchange ranged-for for a classic for loop.
For ranged-for to work, Chains must be of a type that implements an iterator interface, or must be an array.
If it's an array, you know what to do.
Otherwise, you can write the loop as:
for (auto it = Chains.begin(), end = Chains.end(); it != end; ++it)
{
auto block = *it;
Do_Somethin();
}
(Though, possibly, you may need cbegin() if only a const interface is available and begin() has no const overload for some reason.)
If the type of Chains supports random access with operator[], you could also try something like this:
for (std::size_t i = 0; i < Chains.size(); ++it)
{
auto block = Chains[i];
Do_Somethin();
}
… though you'll need to look at the documentation to find out what .size() should actually be.
Now of course C doesn't have iterators, or auto, but then it doesn't have classes either. You can choose to substitute replacements for those features as well if you like.
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 4 years ago.
Improve this question
solution 1 :
auto a = A()
Solution 2 :
A a;
I was wondering which one of the two solutions is the best manner to instantiate an object ?
I know that the solution 1 calls the default constructor and then the copy constructor, but I really don't know if there is any advantages of writing that.
Edit: I wrote a small class to test by my own and it appears that in accordance with the comments, these two "solutions" have exactly the same behavior.
class A
{
public:
A(){
std::cout <<"default_constructor\n";
}
A(const A &g){
std::cout <<"copy_constructor\n";
}
};
solution 1 :
default_constructor
solution 2 :
default_constructor
In my opinion you should always use solution 2 for this case, as you have to define the type somewhere. I prefer using auto just in cases where the type is already set and I can avoid duplicate the type e.g. getting an element from an container
std::vector<double> myVector{0.0, 1.0};
auto firstElement = myVector.front();
or
auto myInt = static_cast<int>(2.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 4 years ago.
Improve this question
I am trying to find an element in an array/list with some strict conditions. I try to find the element again with relaxed conditions if none of the elements satisfy the strict conditions.
for( ele : list) {
if(con1 && cond2 && cond3) {
return ele;
}
}
for( ele : list) {
if(con1 && cond2) {
return ele;
}
}
.....
Should I add a for loop with relaxed conditions each time? Is there a better way?
Better means less coding and good code readability.
Basic answer
I guess this all depends heavily on how many conditions there are and how complex they are. If it's only three separate conditions then yes, I would write something similar to your code. It's simple and easy to read and maintain.
In more complex situations
If there are many more conditions (like 10 or so) or you anticipate there will be more that needs to be added, you might consider using lambdas together with a vector instead:
// sample conditions for integers. Most strict condition is
// an even integer greater than 2 and less than 10
const std::vector<std::function<bool(int)>> conditions{
[](int elem) {return elem < 10;},
[](int elem) {return elem > 2;},
[](int elem) {return elem % 2 == 0;}
// add as many more conditions you wish...
// top condition is the one that will be relaxed first
};
// This will bit-by bit relax the conditions by ignoring more and more of them
auto start_iterator = conditions.begin();
while (start_iterator != conditions.end())
{
for (const auto& elem : list)
{
bool fulfills_all = std::all_of(start_iterator, conditions.end(), [] (std::function<bool(int)> cond) {
// for each active condition, test the condition on the element
return cond(elem);
});
if (fulfills_all)
return elem;
}
// If we get here, that means no element fulfilled all the conditions.
// Relax them by ignoring one more
start_iterator++;
}
// If we reach this point, then no element fulfilled even the most relaxed condition
Haven't really tested this, so some syntax may be a bit rusty but the general idea of it should work. The use of lambdas in std::function wrappers in a vector allow for a large number of conditions only having to be coded once, and std::all_of allows us to iterate over many conditions and verify that each of them are fulfilled for a certain element.
This requires the <functional> and <algorithm> headers.
If you are unfamiliar with std::function or std::any_of then these are helpful sites:
http://en.cppreference.com/w/cpp/utility/functional/function
http://en.cppreference.com/w/cpp/algorithm/all_any_none_of
Your description is pretty ambiguous, but I suspect you're looking for something like (incomplete pseudo-code).
// assuming the relaxed conditions are a subset of the strict conditions
whatever_type relaxed_return_value;
bool relaxed_found = false;
for (auto &element : some_list)
{
if (cond1 && cond2) // check relaxed conditions first
{
if (cond3) // check remaining strict conditions
{
return element; // return immediately on matching strict conditions
}
else if (!relaxed_found)
{
relaxed_return_value = element;
relaxed_found = true;
}
}
}
if (relaxed_found)
return relaxed_return_value;
else
indicate_no_value_found();
The above returns immediately if an element is found that matches the strict conditions, otherwise keeps going and keeps track of the first element that matches the relaxed conditions. If the loop completes, there has been no element matching the strict conditions, and the first result matching relaxed conditions (if any) is identified.
If there is a value of whatever_type (i.e. of an element) that can indicate no data (e.g. it's a pointer and NULL indicates it points at nothing) the logic can be simplified from the above (e.g. no need for bool value to keep track of whether a result has been found for relaxed criteria).
As to whether this is "better", that is completely subjective. Main advantage of this approach over two loops is that no tests will be repeated if no elements meet strict requirements. The downside is additional book-keeping to keep track of the first match of relaxed tests until all elements have been checked against strict criteria.
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 6 years ago.
Improve this question
#include <vector>
int main()
{
std::vector< int > vi;
// This is legal.
for( std::vector< int >::iterator it = vi.begin(); it != vi.end(); ++it )
{
}
// This is not legal. WHY NOT?
// Compiler knows vi's type, as evident from the c++11 syntax for such loop:
// for( auto it : each vi )
// So why not support :: on objects of known type?
for( vi::iterator it = vi.begin(); it != vi.end(); ++it )
{
}
return 0;
}
Because vi is a variable, not a type, and :: can only be applied to a type or a namespace. If you want to get the type so you can use ::, use decltype:
for( decltype(vi)::iterator it = vi.begin(); it != vi.end(); ++it )
As java shows, :: is actually complete unnecessary -- the language could have use . instead, as context is always enough to tell what is going on. Whether that makes for a better or worse language is entirely subjective.
It could be done, by making variable::x equivalent to decltype(variable)::x in some cases.
It simply was not.
There is no "reason" for it.
Sorry not to be more helpful.
Feel free to suggest it to the committee, on the std-discussion mailing list!
Why doesn't it? Here's a few ideas:
There is no authoritative answer. Read this.
Nobody's proposed such a thing. Have at it.
In every context in which you have a variable, you already have the type of that variable, so you could always just use the type anyway.
:: is called the scope resolution operator. Classes have scope. Namespaces have scope. Variables do not have scope.
There's already a reasonable workaround. Can't do vi::iterator but you can do decltype(vi)::iterator so why clutter the language?