This code compiles in Visual Studio 2015 update 3 (and here: visual C++ compiler online , and does not in other compilers I have tried online (GCC and CLANG), giving a redeclaration error
vector<int> v = {1,2,3};
for (auto i : v) {
printf("%d ", i);
int i = 99;
printf("%d ", i);
}
output: 1 99 2 99 3 99
VS C++ online compiler (version: 19.10.24903.0) warns about this:
warning C4456: declaration of 'i' hides previous local declaration
Is there some space in the C++11 spec to allow for both implementations to be valid?
Seems to me that VS2015 is creating a scope for the "auto i", and an inner scope for the loop body.
Adding an extra scope, as a colleague suggested, compiles fine in the other compilers I have tested (not that I wanted this, it's just for curiosity):
vector<int> v = {1,2,3};
for (auto i : v) {{
printf("%d ", i);
int i = 99;
printf("%d ", i);
}}
thanks
EDIT:
Ok, after reading this other question Redeclaration of variable in range-based for loops and the answer from "Angew", I believe that VS is actually correct.
I am reading here: cpp reference
Given this grammar description:
for ( range_declaration : range_expression ) loop_statement
and what this is equivalent to:
{
auto && __range = range_expression ;
for (auto __begin = begin_expr, __end = end_expr;
__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
I understand that loop_statement is actually my entire block including the brackets, so the redefinition is indeed in an inner block, hence valid.
EDIT 2:
My last edit, for future reference, reading the traditional for loop grammar is a similar situation (cpp for loop) as the range-based:
for ( init-statement condition(optional); iteration_expression(optional) ) statement
"The above syntax produces code equivalent to:"
{
init_statement
while ( condition ) {
statement
iteration_expression ;
}
}
So looking back, I could also interpret/parse statement as my inner block, including the braces, for which I would at least expect a consistent behavior in which ever compiler I am. But ALL compilers will bail out with a redeclaration error for the traditional for-loop.
N4606 (C++17 draft) 3.3.3 basic.scope.block, section 4 says
Names declared in the
init-statement
, the
for-range-declaration
, and in the
condition
of
if
,
while
,
for
, and
switch
statements are local to the
if
,
while
,
for
, or
switch
statement (including the controlled statement),
and shall not be redeclared in a subsequent condition of that statement nor in the outermost block (or, for
the
if
statement, any of the outermost blocks) of the controlled statement; see 6.4
shortened:
Names declared in the ... for-range-declaration ... are local to the ... for ... and shall not be redeclared in a subsequent condition of that statement nor in the outermost block
I read this as saying it should not be allowed.
Is there some space in the C++11 spec to allow for both implementations to be valid?
With one exception the only answer to that is no.
The exception is for global variables, where you can use the scoping operator :: to reach them. Otherwise, if you shadow the name of a variable in an outer scope, you no longer have access to it.
Related
When does a C++ program throw this error message:
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::at: __n (which is 0) >= this->size() (which is 0)
Aborted (core dumped)
I was trying an algorithm problem on a website.
My function was:
int stringSimilarity(string s)
{
int size=s.size(), sum=0;
for(int i=0; i<size; i++)
{
string sub_str; int temp_sum=0;
//Creating a substring for comparison
for(int j=i, l=0; j<size, l<size-i; j++, l++)
{
sub_str.at(l)=s.at(j);
}
if(sub_str.at(0)==s.at(0))
{
temp_sum++;
int k=1;
while(sub_str.at(k)==s.at(k))
{
temp_sum++;
k++;
}
}
sum=sum+temp_sum;
}
return sum;
}
While running sample test cases, I got the error message I showed above. Can someone please tell me where am I going wrong?
EDIT:
Made the question to the point. In the original question, I had asked why my program was not compiling. But as many pointed out, it is not a compilation error, but a run-time error thrown by the program.
From documentation of std::string::at()
The function automatically checks whether pos is the valid position of
a character in the string (i.e., whether pos is less than the string
length), throwing an out_of_range exception if it is not.
In here, sub_str is an empty string (length 0), but you try to access it in the first line of your inner loop:
sub_str.at(l)=s.at(j);
One way to overcome it could be to initialize the string to have the same length of s, and edit it in place.
I have faced the same issue when I was doing code on HackerRank,So let me tell you what was my mistake:
I was taking one extra input which was not mentioned in test case so when i removed that my problem got solved.
Program was saying user will give two queries and i have to work on those queries but I was taking the query numbers too.
It was like
cin >> query;
And then i was taking 2 query q1 and q1 so during run time compiler said Abort Called and when i remove this(cin >> query;) line,My program worked fine.
Missing equal sign inside assignment (typing = instead of ==) make unwanted assignment inside a condition statement.
For example, consider the scenario below (this example is in C, but the question is valid also for interpreted code).
CASE A:
int g=1;
if ( g == 3 )
{
printf("g is 3");
}
else
{
printf("g is not 3");
}
//this return: "g is not 3"
CASE B: (typo: missing = inside condition)
int g=1;
if ( g = 3 )
{
printf("g is 3");
}
else
{
printf("g is not 3");
}
//this return: "g is 3" because of the assignment
Both the cases are formally correct, so the code will work but not as we want; and may be hard to debug.
How to prevent this situation? There is a solution that cover the interpreted code (for example javascript), apart static analyzers?
The thing is, using an assignment inside a condition body for if, while, or for is perfectly valid C and is very often used intentionally. For example, I often find myself using the following skeleton code to create a window when writing a Win32 API GUI:
if((hWnd = CreateWindowExW(...)) == NULL)
{
MessageBoxW(NULL, L"Window creation failed", L"Error", MB_OK | MB_ICONSTOP);
return GetLastError();
}
If the test is solely for equality and you want to avoid using the = operator accidentally, one thing you can do is get into the habit of putting the r-value on the left side of the operator, so that if you accidentally use =, it will produce a compilation error:
char *p = malloc(100000);
if(NULL == p)
{
// handle null pointer
}
Obviously, this only works if at least one side of the comparison is an r-value or a const variable.
i have declared a map below using stl and inserted some values in it.
#include<bits/stdc++.h>
int main()
{
map<int,int> m;
m[1]=1;
m[2]=1;
m[3]=1;
m[4]=1;
m[5]=1;
m[6]=1;
for(auto it=m.begin();it!=m.end();)
{
cout<<it->first<<" "<<it->second<<endl;
it=it++;
}
return 0;
}
When i executed the above written code it ended up in an infinite loop. Can someone tell me why it does so?
I am incrementing the value of iterator it and then it gets stored in it which should get incremented next time the loop is executed and eventually it should terminate normally.Am i wrong?
The bad line is it = it++;. It is undefined behavior! Because it is not defined, when it is increased, in your case it is increased before the assingment to itsself again, that the value of it before it is increased is assigned to it again and so it keeps at the first position. The correct line would be it = ++it; or only ++it;/it++;, because it changes itsself.
Edit
That is only undefined with the builtin types, but in here that is defined by the source-code of the map in the stl.
If you try doing something similar with an int, you'll get a warning:
int nums[] = { 1, 2, 3, 4, 5 };
for (int i = 0; i < sizeof nums / sizeof *nums; ) {
cout << nums[i] << '\n';
i = i++;
}
warning: operation on 'i' may be undefined [-Wsequence-point]
However, when you're using a class (std::map::iterator) which has operator overloading, the compiler probably isn't smart enought to detect this.
In other words, what you're doing is a sequence point violation, so the behavior is undefined behavior.
The post-increment operation would behave like this:
iterator operator ++ (int) {
auto copy = *this;
++*this;
return copy;
}
So, what happens to your increment step is that iterator it would get overwritten by the copy of its original value. If the map isn't empty, your loop would remain stuck on the first element.
When reading "The C++ Programming Language, 4th Edition" by Bjarne Stroustrup, section 42.2.4 join() of the new thread class in STL. It has an example code, that confuses me.
void run(int i, int n) // warning: really poor code
{
thread t1 {f};
thread t2;
vector<Foo> v;
// ...
if (i<n) {
thread t3 {g};
// ...
t2 = move(t3); // move t3 to outer scope
}
v[i] = Foo{}; // might throw
// ...
t1.join();
t2.join();
}
It has these comments after the code snippet:
Here, I have made several bad mistakes. In particular:
We may never reach the two join()s at the end. In that case, the
destructor for t1 will terminate the program.
We may reach the two join()s at the end without the move t2=move(t3) having executed. In that case, t2.join() will terminate the program.
Why we may never reach the two joins(), why the destructor for t1 is called before t1.join()?
I added openMp code to some serial code in a simulator applicaton, when I run a program that uses this application the program exits unexpectedly with the output "The thread 'Win32 Thread' (0x1828) has exited with code 1 (0x1)", this happens in the parallel region where I added the OpenMp code,
here's a code sample:
#pragma omp parallel for private (curr_proc_info, current_writer, method_h) shared (exceptionOccured) schedule(dynamic, 1)
for (i = 0 ; i < method_process_num ; i++)
{
current_writer = 0;
// we need to add protection before we can dequeue a method from the methods queue,
#pragma omp critical(dequeueMethod)
method_h = pop_runnable_method(curr_proc_info, current_writer);
if(method_h !=0 && exceptionOccured == false){
try {
method_h->semantics();
}
catch( const sc_report& ex ) {
::std::cout << "\n" << ex.what() << ::std::endl;
m_error = true;
exceptionOccured = true; // we cannot jump outside the loop, so instead of return we use a flag and return somewhere else
}
}
}
The scheduling was static before I made it dynamic, after I added dynamic with a chunk size of 1 the application proceeded a little further before it exited, can this be an indication of what is happening inside the parallel region?
thanks
As I read it, and I'm more of a Fortran programmer than C/C++, your private variable curr_proc_info is not declared (or defined ?) before it first appears in the call to pop_runnable_method. But private variables are undefined on entry to the parallel region.
I also think your sharing of exception_occurred is a little fishy since it suggests that an exception on any thread should be noticed by any thread, not just the thread in which it is noticed. Of course, that may be your intent.
Cheers
Mark