Im seeing some examples of inline const variable getting initialized (and destructed) 3 times with visual studio 2017. Is this is a bug with the linker ? or is this supposed to happend in some other way ?
linker Comdat folding is set to Off.
Example Code:
#pragma once
struct A {
A() {
static int count = 0;
++count;
ASSERT(count == 1);
}
~A() {
}
};
inline const A a = A();
In my solution, I have the assert fire twice (A constructor called 3 times).
Inspecting the call stack shows all call stacks are identical and all calls come from dynamic initializer for a(). Now I know for a fact this class is not used in other parts of the solution since I just created it to investigate this issue.
Im using VS17 15.8.9
Update: Bug report here https://developercommunity.visualstudio.com/content/problem/297876/static-inline-variable-gets-destroyed-multiple-tim.html (you may upvote to help push for the bugfix)
This appears to be an MSVC bug. I'm able to reproduce it with the code below (also with VS2017 15.8.9). Interestingly, I can only reproduce with a Debug build. In Release mode, the optimizer seems to save us.
Common.h
#pragma once
#include <iostream>
class Foo
{
public:
Foo()
{
std::cout << "Constructing a Foo" << std::endl;
}
~Foo()
{
std::cout << "Destructing a Foo" << std::endl;
}
};
inline Foo const Bar;
other.cpp
#include "common.h"
void DoOtherStuff()
{
std::cout << &Bar << std::endl;
}
main.cpp
#include "common.h"
void DoStuff()
{
std::cout << &Bar << std::endl;
}
extern void DoOtherStuff();
int main()
{
DoStuff();
DoOtherStuff();
}
Output (Debug)
Constructing a Foo
Constructing a Foo
00007FF74FD50170
00007FF74FD50170
Destructing a Foo
Destructing a Foo
I get the bug in both debug and release (/Ox) mode using the MS C++ compiler version 19.16 (comes with, e.g., Visual Studio 15.9.4).
Inline.Hpp
#include <iostream>
inline struct Foo
{ Foo() { std::cout << "Constructing a Foo at " << this << std::endl; } }
Instance;
Inline.cpp
#include "Inline.Hpp"
int main() { return 0; }
Inline2.cpp
#include "Inline.Hpp"
After compiling and linking inline.cpp and inline2.cpp, the output on running is:
Constructing a Foo at 00BE4028
Constructing a Foo at 00BE4028
The compiler and linker correctly resolve the two inline definitions to a single object, but incorrectly call the constructor for each definition, instead of just once. This is a serious bug which renders the "inline variable" feature of C++17 unusable. The "workaround" is to regard inline variables as still unsupported by MS C++ as of version 19.16, even when the /std:c++17 switch is used.
As of today there is an update for visual studio 2017 to version 15.9.24 which fixes the problem.
From the release notes:
Fixed C++ compiler bug for proper folding of inline variable dynamic
initializers.
Related
I've lost almost all day tracking bug in my program. For some reason, my implementation of std::apply in terms of c++11 was faulty: arguments to the underlying function somehow got empty in the middle of call. Good example is std::unique_ptr that after call to a makeshift function (below, foo()) was always empty() in the body of called function.
I've dumbed down my code to a simple test case:
#include <tuple>
#include <memory>
#include <iostream>
struct Foo
{
Foo()
{
std::cout << "Foo()" << std::endl;
}
~Foo()
{
std::cout << "~Foo()" << std::endl;
}
};
template <typename ...Args>
void foo(Args && ...args)
{
using TupleType = decltype(std::make_tuple(std::forward<Args>(args)...));
std::cout << "Point #1" << std::endl;
/// Package arguments to a function.
auto && packaged_args = std::make_shared<TupleType>(std::make_tuple(std::forward<Args>(args)...));
std::cout << "Point #2" << std::endl;
}
int main()
{
std::unique_ptr<Foo> foo_var{new Foo};
foo(std::move(foo_var));
return 0;
}
If compiled with clang together with libc++ (-stdlib=libc++) the results are:
Foo()
Point #1
~Foo()
Point #2
Live example on coliru.stacked-crooked.com
The results are obviously incorrect. If compiled with clang, but without libc++, or if compiled with gcc, the results are as expected:
Foo()
Point #1
Point #2
~Foo()
I found a laughable workaround for the combination of clang and libc++, replace:
auto && packaged_args = std::make_shared<TupleType>(std::make_tuple(std::forward<Args>(args)...));
with:
std::shared_ptr<TupleType> packaged_args{new TupleType(std::make_tuple(std::forward<Args>(args)...))};
and it again works as expected.
Live example on coliru.stacked-crooked.com
The qustion is: is it an UB, so that both compilers are right with the wrong code or the code is okay and this is a bug?
This seems to be a bug in libc++'s tuple implementation.
The bug exists in Libc++ <= 3.8, but has been fixed by my tuple rewrite in 3.9.
Sorry about the bug; it appears the best/only way to avoid it is upgrade.
The sample below shows reading an uninitialized field a.i1 in two ways. The first call does not compile. However, calling a.donothing() that does not do anything, the original call compiles fine and prints the default value 0. Why is this inconsistency?
I am using Visual Studio Community 2015, the compiler output is as follows:
Severity Code Description Project File Line Suppression State
Error C4700 uninitialized local variable 'a' used
class A {
public:
int i1;
void donothing() {}
};
int main() {
A a;
cout << "main1: " << a.i1 << endl; // compile fails
a.donothing();
cout << "main2: " << a.i1 << endl; // prints 0 (default)
return 0;
}
Compiler is doing what it ought to do. You can fix it like this (as one solution out of many):
class A {
public:
A(int i = 0) : i1(i) {}
int i1;
void donothing() {}
};
In both cases a warning must be issued, at most. The fact that calling donothing cancels the error is a clear indication that this is a bug. You can report it at Microsoft Connect.
A simple workaround for this problem is to change the declaration to A a{};.
You can test your code on different compilers at Compiler Explorer.
[EDIT] The warning message C4700 is treated as an error if Security Development Lifecycle is turned on (/sdl).
Depends on the compiler, the compiler should supply a default constructor that will initialize your members with a default value. But this behavior is not dependable. Since C++11 you can say ClassName()=default; The best practice is to prove your own default constructor.
Your code never had any compiler errors with g++ 5.4.0
#include <iostream>
using namespace std;
class A {
public:
//A() : i1(0) { } // compiler will provide this if you don't write anything
// since C++ 11 you can also say A() = default;
A() = default;
int i1;
void donothing() {}
void writeMember() const { cout << "i1 value: " << i1 << endl; }
};
// better provide a signature for the main function
int main(int argc, char* argv[]) {
A a;
a.writeMember();
cout << "main1: " << a.i1 << endl; // compile fails
a.donothing();
cout << "main2: " << a.i1 << endl; // prints 0 (default)
return 0;
}
To compile the above code stored in testclass.cpp
g++ -std=c++11 -o testclass testclass.cpp
By using the C++11 default I got
i1 value: 4196976
main1: 4196976
main2: 4196976
If you comment out A()=default; this will rely on the compiler provided initializer, or the compiler may be lazy and not doing anything for performance reasons. You get
i1 value: 4196944
main1: 4196944
main2: 4196944
If you uncomment the line after public: you should consistently get 0
This illustrates the importance of adhering to good conventions of alway provide your own default constructor. The compiler maybe doing the right thing by not assigning any particular value to your member because you may assign another value in the next operation. This can save one operation. The member will be simply allocated on the stack, in that case the member got a random value. If you run this code on a different computer you will for sure get a different value.
I want to have a method with a function object with default value as parameter, to be called with a lambda function, like for example:
#include <iostream>
#include <functional>
void func(const std::function<void()>& f = {}){
if(f) f();
else std::cout << "or not" << std::endl;
}
int main() {
func([](){ std::cout << "hello" << std::endl; });
func();
}
but on Visual Studio 2012 this does not compile (it compiles using Visual Studio 2015 or g++, for example), complaining about the default value {}. Change this to:
void func(const std::function<void()>& f = nullptr){
fix the problem.
1) Is that a feature not supported by the compiler?
2) Is there any difference between both?
1) Is that a feature not supported by the compiler?
Your test appears to show that is the case. It is a standard feature, so not supporting it means that the compiler doesn't conform to the standard.
2) Is there any difference between both?
There is no difference. Both the default constructor and the constructor that takes nullptr_t behave exactly the same.
When I use the __FUNCTION__ macro/variable to print out debugging information, there seems to be a difference in what it outputs when using the Microsoft C++ compiler and gcc. For example, using the following trivial code:
class Foo
{
public:
void Bar(int a, int b, int c)
{
printf ("__FUNCTION__ = %s\n", __FUNCTION__);
}
};
int main (void)
{
Foo MyFoo;
MyFoo.Bar();
return 0;
}
Using the Microsoft Visual C++ compiler, I get
__FUNCTION__ = Foo::Bar
whereas when compiling using gcc (in this case on the Mac), I get
__FUNCTION__ = Bar
The second example is not ideal because I quite often have several classes with, say, Init() and Uninit() methods and in a debug output trace its virtually impossible to tell which one of these has been called as the class name will be missing. Now, I know you can use the __PRETTY_FUNCTION__ in place of __FUNCTION__ to get something like
__PRETTY_FUNCTION__ = void Foo::Bar(int, int, int)
Which is fine, but its a bit too verbose for what I need and gets a bit long for functions with a lot of parameters.
So my question is (at last), is there any way to get the output to look like simply Foo::Bar using gcc, as in the example above?
If you are using it for tracing, you can always use typeid(T).name() and just conditionally compile per platform. Certainly not as convenient as the macro, but it could work.
Vaguely similar to __CLASS__ macro in C++
The function-name sanctioned by the standard is defined as follows:
static const char __func__[] = "function-name ";
Example:
#include <iostream>
namespace meh {
void foobar() { std::cout << __func__ << std::endl; }
};
struct Frob {
void foobar() { std::cout << __func__ << std::endl; }
static void barfoo() { std::cout << __func__ << std::endl; }
};
int main () {
std::cout << __func__ << std::endl;
meh::foobar();
Frob().foobar();
Frob::barfoo();
}
However, output with g++:
main
foobar
foobar
barfoo
However, that is valid C++ behaviour:
ยง 8.4.1, 8: The function-local predefined variable __func__ is defined as if a definition of the form static const char __func__[] = "function-name ";
had been provided, where function-name is an implementation-defined string. It is unspecified whether such a variable has an address distinct from that of any other object in the program
I.e., you may not trust in its value. If you want to use non-portable extensions, have a look at a similar question: What's the difference between __PRETTY_FUNCTION__, __FUNCTION__, __func__? .
Playing around with MSVC++ 2005, I noticed that if the same class is defined several times, the program still happily links, even at the highest warning level. I find it surprising, how comes this is not an error?
module_a.cpp:
#include <iostream>
struct Foo {
const char * Bar() { return "MODULE_A"; }
};
void TestA() { std::cout << "TestA: " << Foo().Bar() << std::endl; }
module_b.cpp:
#include <iostream>
struct Foo {
const char * Bar() { return "MODULE_B"; }
};
void TestB() { std::cout << "TestB: " << Foo().Bar() << std::endl; }
main.cpp:
void TestA();
void TestB();
int main() {
TestA();
TestB();
}
And the output is:
TestA: MODULE_A
TestB: MODULE_A
It is an error - the code breaks the C++ One Definition Rule. If you do that, the standard says you get undefined behaviour.
The code links, because if you had:
struct Foo {
const char * Bar() { return "MODULE_B"; }
};
in both modules there would NOT be a ODR violation - after all, this is basically what #including a header does. The violation comes because your definitions are different ( the other one contains the string "MODULE_A") but there is no way for the linker (which just looks at class/function names) to detect this.
The compiler might consider that the object is useless besides its use in Test#() function and hence inlines the whole thing. That way, the linker would never see that either class even existed ! Just an idea, though.
Or somehow, linking between TestA and class Foo[#] would be done inside compilation. There would be a conflict if linker was looking for class Foo (multiple definition), but the linker simply does not look for it !
Do you have linking errors if compiling in debug mode with no optimizations enabled ?