Why are (member) function pointers behaving so weirdly in Visual C++? - c++

I've had a really bizarre problem that I've reduced to the following test case:
#include <iostream>
#include <map>
#include <string>
struct Test
{
std::map<std::string, void (Test::*)()> m;
Test()
{
this->m["test1"] = &Test::test1;
this->m["test2"] = &Test::test2;
}
void test1() { }
void test2() { }
void dispatch(std::string s)
{
if (this->m.at(s) == &Test::test1)
{ std::cout << "test1 will be called..." << std::endl; }
else if (this->m.at(s) == &Test::test2)
{ std::cout << "test2 will be called..." << std::endl; }
(this->*this->m.at(s))();
}
};
int main()
{
Test t;
t.dispatch("test1");
t.dispatch("test2");
}
It outputs
test1 will be called...
test1 will be called...
when optimizations are enabled, which is really bizarre. What's going on?

This is a by-product of what Visual C++ refers to as Identical COMDAT Folding (ICF). It merges identical functions into a single instance. You can disable it by adding the following switch to the linker commandline: /OPT:NOICF (from the Visual Studio UI it is found under Properties->Linker->Optimization->Enable COMDAT Folding)
You can find details at the MSDN article here: /OPT (Optimizations)
The switch is a linker-stage switch, which means you won't be able to enable it just for a specific module or a specific region of code (such as __pragma( optimize() ) which is available for compiler-stage optimization).
In general, however, it is considered poor practice to rely on either function pointers or literal string pointers (const char*) for testing uniqueness. String folding is widely implemented by almost all C/C++ compilers. Function folding is only available on Visual C++ at this time, though increased widespread use of template<> meta-programming has increased requests for this feature to be added to gcc and clang toolchains.
Edit: Starting with binutils 2.19, the included gold linker supposedly also supports ICF, though I have been unable to verify it on my local Ubuntu 12.10 install.

It turns out Visual C++'s linker can merge functions with identical definitions into one.
Whether that's legal or not according to C++, I have no idea; it affects observable behavior, so it looks like a bug to me. Someone else with more information may want to chime in on that though.

C++11 5.3.1 describes what & does; in this instance, it gives you a pointer to the member function in question, and the passage makes no requirement that this pointer must be unique.
However, 5.10/1 says about ==:
Two pointers of the same type compare equal if and only if they are both null, both point to the same function, or both represent the same address.
The question then becomes... are test1 and test2 "the same function"?
Though the optimizer has collapsed them into a single definition, arguably the two names identify two functions and, as such, this would seem to be an implementation bug.
(Note, though, that the VS team don't care and consider it "valid enough" to warrant the benefits of the optimisation. That, or they don't realise that it's invalid.)
I'd stick to using the strings as "handles" for your function pointers.

Related

Why thread still work with deleted variable?

I expect to crash program with this code:
void f(int& ref)
{
for (auto i{0}; i < 0xfffff; ++i)
{
std::clog << i << ":" << ref++ << std::endl;
}
}
void run(void)
{
int n = 10;
std::thread(f, std::ref(n)).detach();
}
int main(void)
{
run();
std::this_thread::sleep_for(3s);
}
I have GCC 9.3 and compile above program with default parameters. When i run the program i expect to crash which in void f(int&); function we no longer have local int n; variable decelered in void run(void); function, but it's clearly run the program and increase ref variable each time and printed until the 3 second sleep in main function get over. Where i do wrong ?
Your code has undefined behavior because you are using a reference to access an object whose lifetime already ended. There are some special rules regarding extension of lifetime when binding to a const reference, but that does not apply here.
The C++ standard never guarantees that your program will crash if you make a mistake. The C++ standard only specifies what you get when you compile and run valid code. There would be no gain from specifiying things like "If you dereference a null pointer you will get a segmentation fault". Instead the standard specifies what is valid code and mostly stays silent about what happens when you write invalid C++ code. In a nutshell, this is what undefined behavior is.
Repeating a comment of mine:
If you cross a streed when the lights are red, you will not necessarily get hit by car. It just means you should not cross the streets when there are red lights (and when you do you might be hit by a car).
As any analogy this isn't a perfect one. Even if you don't see a car coming and you know that you will not get hit, you should not "cross the street" when "the lights are red". That is because code that relies on undefined behavior like yours may appear to work today, but tomorrow with a different compiler, different version of same compiler, or even same compiler targeting a different platform, bad things may happen.

Creating an rvalue and passing it to a function by forwarding

I have this code which seems to work, but I'm not sure if I'm just seeing undefined behaviour or it's actually working.
#include <string>
#include <vector>
#include <sstream>
#include <numeric>
#include <iostream>
auto main() -> int {
const std::vector<std::string> keywords = {
"and","and_eq","asm","auto","bitand", "bitor","bool","break","case",
"catch","char","class","compl","const", "const_cast","continue",
"default","#define","delete","do","double","dynamic_cast","else","enum",
"explicit","export","extern", "extern \"C\"","false","float",
"for","friend","goto","if","inline","int","long","mutable","namespace",
"new","not","not_eq","operator","or", "or_eq","private","protected",
"public","register","reinterpret_cast","short","signed","sizeof",
"static","static_cast","struct","switch","template","this","throw",
"true","try","typedef","typeid","typename","union","unsigned","using",
"virtual","void","volatile","void","wchar_t","while","xor","xor_eq",
"return", "decltype"
};
std::ostringstream keywords_pattern =
std::accumulate(keywords.begin(), keywords.end(), std::forward<std::ostringstream>(
std::ostringstream("constexpr", std::ostringstream::ate)),
[](std::ostringstream &accum, const std::string& next) -> std::ostringstream&& {
accum << '|' << next;
return std::forward<std::ostringstream>(std::move(accum));
});
std::cout << keywords_pattern.str() << std::endl;
}
What it does:
All this does is combine the vector of C++ keywords into a string seperated by |.
Output:
This is the output when I run it:
onstexpr|and|and_eq|asm|auto|bitand|bitor|bool|break|case|catch|char|class|compl|const|const_cast|continue|default|#define|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|extern "C"|false|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|not|not_eq|operator|or|or_eq|private|protected|public|register|reinterpret_cast|short|signed|sizeof|static|static_cast|struct|switch|template|this|throw|true|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|void|wchar_t|while|xor|xor_eq|return|decltype
No this is not a mistake, it is indeed missing the first character from the output, even though I fail to see how, hence the more reason why I felt certain there was something I was doing wrong.
My concerns:
I am especially worried it might have some undefined behaviour because the function is manipulating a temporary (the ostringstream) through a reference; and finally returning...an rvalue reference??
That's where I need help with understanding how to make sure I am not doing something wrong. Also, with my use of forwarding and move semantics, are there any improvements I can make there? Suggest away.
Compiled with:
Compiles with no warnings or errors on GCC and Clang.
std::accumulate, std::ostringstream and the standard
std::accumulate requires that T (the return type and the type of the initial value) is CopyAssignable and CopyConstructible. std::ostringstream is neither CopyAssignable nor CopyConstructible, so as far as the standard is concerned, it's not allowed. (In fact, MSVC throws a big red error in your face!).
Interestingly, neither GCC nor clang nor icc (the ons i tested) produce even a warning (with -pedantic), though I don't know whether that's a bug (doesn't warn about std::ostringstream not being CopyAssignable or CopyConstructible) or a feature (do they explicitly support move-only types for std::accumulate?).
Anyways, even if they were to support it, it's not in the standard, so they could technically do as they want.
TLDR: It isn't allowed according to the standard.
Implementation
There's no need for std::forward in this code.
In the first usage, the std::ostringstream constructor already returns a rvalue reference.
In the second usage, you already explicitly turned accum into a rvalue reference by calling std::move.
std::forward is useful in templates, where the type of the variable to be forwarded gets deduced, so you don't know whether it can/should be moved or copied. Example:
template<typename T>
void do_something(T&& thing) {
call_impl(std::forward<T>(thing));
}
do_something(std::string("text")); // calls call_impl(std::string&&);
std::string example{"text"};
do_something(example); // calls call_impl(std::string&) or call_impl(const std::string&)
Also, consider replacing std::endl with '\n', unless you explicitly want to flush the stream.
Your issue (the corrupted first character) can be reduced to the following:
#include <string>
#include <sstream>
#include <iostream>
int main()
{
std::ostringstream myStream("constexpr", std::ostringstream::ate);
myStream = std::move(myStream);
std::cout << myStream.str() <<std::endl;
return 0;
}
Which sure looks like a bug in GCC to me.
It works fine in Visual Studio 2013 but the problem is reproduced with
mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev0

Can C/C++ optimizers decide to lazily evaluate values that are only used in a short-circuit evaluation?

I like to refactor complicated conditionals like this:
if (foo(blah) || (bar(param1, param2, param3) && !obj.longMethodName())) ...
into this:
bool foo_true = foo(blah);
bool bar_true = bar(param1, param2, param3);
bool long_true = obj.longMethodName();
if (foo_true || (bar_true && !long_true)) ...
I think this makes the code a lot easier to understand, and it helps with debugging because you can see the intermediate results used to compute the final condition.
But: in the original code, due to short circuiting, bar will only be evaluated if foo returns true, and longMethodName only if bar returns true.
Assume that functions are "pure", methods are const, and the compiler can see the function bodies of everything. Are C++ optimizers allowed to defer evaluating my intermediate values until they are needed?
Of course. Provided the compiler can see enough to determine
that foo, bar and obj.longMethodName() don't have any
other impact on the observable behavior of your code.
Whether any compilers do is another question. I rather doubt
it; it would require some very special logic, which isn't in the
usual list of optimization techniques, for something that
practically nobody does. (I suspect that most programmers would
find the original version, formatted correctly, to be more
readable than the one with a lot of extra variables.)
EDIT:
I wonder if it's worth pointing out that the compiler is allowed
to call all three functions even if the if is written:
if ( foo( blah ) || (bar( p1, p2, p3 ) && ! obj.lMN() ) )
(Although I can't imagine one that would.) The standard makes
no requirements with regards to which functions are called when;
it only requires that the observable behavior be the same (same
values and in the same order---no guarantees with regards to
time) "as if" the formal semantics of the program were followed.
And the only things that count as observable behavior is IO
(in some form) and accesses to volatile objects.
No. You compiler is not allowed to make the optimisation because it can not determine wether you have meant the short circuit or wether you want to have a potential side effect of evaluating bar no matter what.
No. C++ has no concept of a pure method with no side effects, so there really isn't a way to optimize that.
The problem here is that foo and bar could be implemented in another compilation unit and C++ does not have the concept of function purity. This means that foo and bar might have side effects (changes to screen or global variables) and therefore must be evaluated in order for you to get expected behaviour.
Interestingly enough, with GCC, functions can be declared with the pure attribute. This tells the compiler that the function does not have any side effects. And therefore can be called lazily. See here for more details.
I am not sure if the assignment would be counted as a side-effect already. To say the least it is probably hard to determine if it is safe to move the actual call.
But, I would like to point out that in c++11 it is possible to achieve what OP pursues with nearly exact same syntax that OP uses in examples utilizing std::bind.
It is just that foo_true, would not be defined as
bool foo_true = foo(blah);
but rather
auto foo_true = std::bind(foo, blah).
The if could be then checked as if( foo_true() || bar_true() ).
Whether it is cleaner or not, is up to personal matter IMO. But I believe it behaves as both wanted, and expected. Full code:
#include <iostream>
#include <functional>
using namespace std;
bool foo(int blah){
cout << "blah: " << blah << '\n';
return blah;
}
bool bar(bool negate_me){
cout << "negate_me: " << negate_me << '\n';
return !negate_me;
}
int main() {
bool test = true;
int param = 42;
auto foo_true = std::bind(foo, test);
auto bar_true = std::bind(bar, param);
if (foo_true() || bar_true() ) cout << "TEST\n";
return 0;
}
Output:
blah: 1
TEST
bar wasn't called. Change test to false and it will be.

What does the fpermissive flag do?

I'm just wondering what the -fpermissive flag does in the g++ compiler? I am getting:
error: taking address of temporary [-fpermissive]
which I can solve by giving the -fpermissive flag to the compiler.
EDIT:
I just found what was causing the temporary address error part! I'm going to fix that part right now.
Right from the docs:
-fpermissive
Downgrade some diagnostics about nonconformant code from errors to warnings.
Thus, using -fpermissive will allow some nonconforming code to compile.
Bottom line: don't use it unless you know what you are doing!
The -fpermissive flag causes the compiler to report some things that are actually errors (but are permitted by some compilers) as warnings, to permit code to compile even if it doesn't conform to the language rules. You really should fix the underlying problem. Post the smallest, compilable code sample that demonstrates the problem.
-fpermissive
Downgrade some diagnostics about nonconformant code from errors to warnings.
Thus, using -fpermissive will allow some nonconforming code to compile.
When you've written something that isn't allowed by the language standard (and therefore can't really be well-defined behaviour, which is reason enough to not do it) but happens to map to some kind of executable if fed naïvely to the compiling engine, then -fpermissive will do just that instead of stopping with this error message. In some cases, the program will then behave exactly as you originally intended, but you definitely shouldn't rely on it unless you have some very special reason not to use some other solution.
If you want a real-world use case for this, try compiling a very old version of X Windows-- say, either XFree86 or XOrg from aboout 2004, right around the split-- using a "modern" (cough) version of gcc, such as 4.9.3.
You'll notice the build CFLAGS specify both "-ansi" and "-pedantic". In theory, this means, "blow up if anything even slightly violates the language spec". In practice, the 3.x series of gcc didn't catch very much of that kind of stuff, and building it with 4.9.3 will leave a smoking hole in the ground unless you set CFLAGS and BOOTSTRAPCFLAGS to "-fpermissive".
Using that flag, most of those C files will actually build, leaving you free to move on to the version-dependent wreckage the lexer will generate. =]
A common case for simply setting -fpermissive and not sweating it exists: the thoroughly-tested and working third-party library that won't compile on newer compiler versions without -fpermissive. These libraries exist, and are very likely not the application developer's problem to solve, nor in the developer's schedule budget to do it.
Set -fpermissive and move on in that case.
The general answer is that it "Downgrades some diagnostics about nonconformant code from errors to warnings."
Unfortunately, I haven't seen a specific list of things that it allows.
My main reason for posting an answer is to suggest that you avoid using it if at all possible. Instead, look at each error and see if it can be fixed. OP found and fixed what was causing their error. ("taking address of temporary" could be something like calling a function that returns a std::string object, and assigning something to the transient object's c_ptr() value.)
I was just reviewing a project that involved upgrading the version of gcc, and the developer added -fpermissive because there were suddenly a bunch of compilation errors. I noticed that one test was:
if (myPointer == '\0')
I pointed out that it really should be:
if (myPointer[0] == '\0')
The developer checked, and it turned out that every single thing flagged was a real error - some of which had been present for over 20 years.
As #cli_hlt mentioned
Bottom line: don't use it unless you know what you are doing!
It can do horrible things such that a compiler sometimes can cancel of constness of variables for std::map:
#include <map>
#include <vector>
#include <iostream>
#include <string>
struct B{
std::map<std::string, int> m_map;
std::vector<int> m_vector;
B(){
m_map["a"] = 1;
m_map["b"] = 2;
m_map["c"] = 3;
m_vector.emplace_back(1);
m_vector.emplace_back(2);
m_vector.emplace_back(3);
}
const std::map<std::string, int>& getMap() const {
return m_map;
}
const int& getMapValue(const std::string& key) const {
return m_map.at(key);
}
const std::vector<int>& getVector() const {
return m_vector;
}
const int& getVectorValue(const int& i) const {
return m_vector[i];
}
};
int main(){
B b;
auto& my_map = b.getMap(); // we get const ref here
my_map["a"] = 10; // here we can modify it
std::cout << "my_map[a]=" << my_map.at("a") << std::endl;
auto& my_map2 = b.getMap(); // here we return already modified variable
std::cout << "my_map2[a]=" << my_map2.at("a") << std::endl;
auto& my_value = b.getMapValue("b");
// my_value = 20; // compiler error
// std::cout << "my_map[b]=" << my_value << std::endl;
auto& my_vector = b.getVector();
// my_vector[0] = 10; // compiler error
// std::cout << "my_vector[0]=" << my_vector[0] << std::endl;
const int a = 10;
auto& a1 = a;
// a1 = 100; // compiler error
}
As you can see you can't guarantee the constness of the map, however, the constness of a vector or value can be preserved.
P.S. here I tested in the following compilers GCC 12.1, 9.1, 8.1, 7.1, 6.1.
However, clang does not -fpermissive flag have this and it will catch the error.

const char* vs char*

Here is what my book says:
char *p="Hello"; //pointer is variable, string is constant
*p='M'; // error
p="bye"; // works
Well, in C my second line does not give me any error, Neither in C++.
I am using Turbo C++ on windows 7. Now is the above thing true if i try in gcc or something else.
Also on the similar lines if the above code is correctly interpreted by the book,
#include<iostream.h>
void display(char*);
void display(const char*);
void main()
{
char* ch1="hello";
const char *ch2="bye";
display(ch1);
display(ch2);
}
void display(char* p)
{
cout << p << endl;
}
void display(const char* p)
{
cout << p << endl;
}
Now is my book considering char* and const char* the same because if it is then the above code shall not work, since arguments will be the same?
(Though i get the output Hello bye on turbo +windows.)
Which one is correct?
The language specification is not a promise that compilers make to you, but a mutual contract that you and compilers both sign onto. (Metaphorically speaking, of course. Obviously it's not a literally legally binding contract.) If you violate the contract by writing *p='M';, then you've triggered "undefined behavior", and you can't expect any specific behavior from the compiler: maybe it will be strict about it and give you a compile error, maybe it will just go wonky at run-time . . . you didn't hold up your end of the bargain, and it's allowed to do literally whatever it wants now. See also: http://catb.org/jargon/html/N/nasal-demons.html.
Question:
“Now is my book considering char* and const char* the same because if it is then the above code shall not work, since arguments will be the same?”
Well you’re probably misrepresenting your book.
It probably does not consider those types to be the same, because they are not the same.
Now to your code:
#include<iostream.h>
[iostream.h] is not part of standard C++. C++ was standardized in 1998, and that standardization dispensed with the ARM era's [iostream.h]. So a modern compiler will likely choke on that.
As a workaround, when you get yourself a less antique compiler, you might do …
#include <iostream>
using namespace std;
Next,
void display(char*);
void display(const char*);
Declaring functions at the top of the file generally just yields extra work. It often means maintaining two declarations of the function. When you could have dealt with just one declaration.
void main()
In standard C and standard C++ main is not allowed to have any other result type than int.
Visual C++ is one compiler that, as a language extension, permits void.
However, it’s quite silly to use that possibility since it is more to write and just makes the code non-standard and likely to not compile with other compilers.
{
char* ch1="hello";
By C++11 rules the above will not compile. It was deprecated in C++98 and removed in C++11. However, AFAIK current compilers still allow it, but some have a warning that can be turned on.
const char *ch2="bye";
display(ch1);
display(ch2);
}
The above is OK, although it would not hurt to add an extra const, like
const char* const ch2="bye";
char* ch1="hello";
is deprecated in C++. The correct way is const char*. Because "hello" is stored in a read only region. Also, int main() or int main(int, char**) is the correct way of defining main().
Don't use Turbo C, it's an outdated compiler. Go for gcc or MSVC. Also, don't use books which provides such incorrect information.
char *p="Hello"; //pointer is variable, string is constant
This code is allowed, because it has been valid since long before the C language got a const keyword.
In order not to break old code, the C and C++ standards just documented that this should work like before.
However, if you write new code you should use the proper form const char*.