several definitions of the same class - c++

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 ?

Related

Wrong symbols linked. Why? [duplicate]

This question already has answers here:
C++ Multiple Definition of Struct
(2 answers)
Why is there no multiple definition error when you define a class in a header file?
(3 answers)
Closed 1 year ago.
C++ translator seems uses correct declared structs of the same name, but then linker mismatches them without any warning or error! And this also leads to UB, because at least inappropriate ctor/dtor are used for the memory region.
Here is minimal sandbox code. Each struct Test should be treated as some internal non-public structure used only in one own .cpp file.
file1.cpp
#include <iostream>
using namespace std;
void someFunc();
struct Test
{
Test() { std::cout << "1 "; }
~Test() { std::cout << "~1" << std::endl; }
};
int main()
{
{
Test test;
}
someFunc();
return 0;
}
file2.cpp
#include <iostream>
struct Test {
Test() { std::cout << "2 "; }
~Test() { std::cout << "~2" << std::endl; }
};
void someFunc() {
Test test;
}
(Downloadable and buildable CMake-project just in case: https://file.io/dzafv409B2t0)
Output will be:
1 ~1
1 ~1
So, I expected:
Successful build with output: 1 ~1 2 ~2
Or failed build with multiple definition error
Yes, I can resolve the problem if:
Rename the struct
Put the struct into anonymous namespace - force internal linkage
...but this doesn't answer the main question:
Why linker behaves so? Why does it silently links to first available matching symbol (among several) instead of reporting multiple definition error?
Update: As I understood, this mechanism allows to include header with class declaration (with inline code) into several different source files without multiple definition problem.

inline variable is initialized more than once

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.

C++ class name collision

For the following C++ code, I'm getting unexpected behavior. The behavior was verified with recent GCC, Clang and MSVC++. To trigger it, it is required to split the code among several files.
def.h
#pragma once
template<typename T>
struct Base
{
void call() {hook(data);}
virtual void hook(T& arg)=0;
T data;
};
foo.h
#pragma once
void foo();
foo.cc
#include "foo.h"
#include <iostream>
#include "def.h"
struct X : Base<int>
{
virtual void hook(int& arg) {std::cout << "foo " << arg << std::endl;}
};
void foo()
{
X x;
x.data=1;
x.call();
}
bar.h
#pragma once
void bar();
bar.cc
#include "bar.h"
#include <iostream>
#include "def.h"
struct X : Base<double>
{
virtual void hook(double& arg) {std::cout << "bar " << arg << std::endl;}
};
void bar()
{
X x;
x.data=1;
x.call();
}
main.cc
#include "foo.h"
#include "bar.h"
int main()
{
foo();
bar();
return 0;
}
Expected output:
foo 1
bar 1
Actual output:
bar 4.94066e-324
bar 1
What I expected to happen:
Inside of foo.cc, an instance of X defined within foo.cc is made and through calling call(), the implementation of hook() within foo.cc is called. Same for bar.
What actually happens:
An instance of X as defined in foo.cc is made in foo(). But when calling call, it dispatches not to hook() defined in foo.cc but to hook() defined in bar.cc. This leads to corruption, as the argument to hook is still an int, not a double.
The problem can be solved by putting definition of X within foo.cc in an other namespace than definition of X within bar.cc
So finally the question: There is no compiler warning about this. Neither gcc, nor clang or MSVC++ did even show a warning about this. Is that behavior valid as defined per C++ standard?
The situation seems to be a bit constructed, but it happened in a real world scenario. I was writing tests with rapidcheck, where possible actions on a unit to be tested are defined as classes.
Most container classes have similar actions, so when writing tests for a queue and a vector, classes with names like "Clear", "Push" or "Pop" may come up several times. As these are only required locally, I've put them in directly in the sources where the tests are execute.
The program is Ill-formed, because it violates the One-Definition Rule by having two different definitions for class X. So it is not a valid C++ program. Note that the standard specifically allows compilers not to diagnose this violation. So the compilers are conforming, but the program is not valid C++ and as such has Undefined Behaviour when executed (and thus anything can happen).
You have two identically named, but different, classes X in different compilation units, rendering the program ill-formed, as there are now two symbols with the same name. Since the problem can only be detected during linking, compilers are not able (and not required) to report this.
The only way to avoid this sort of thing, is to put any code that is not meant to be exported (in particular all code that has not been declared in a header file) into an anonymous or unnamed namespace:
#include "foo.h"
#include <iostream>
#include "def.h"
namespace {
struct X : Base<int>
{
virtual void hook(int& arg) {std::cout << "foo " << arg << std::endl;}
};
}
void foo()
{
X x;
x.data=1;
x.call();
}
and equivalently for bar.cc. In fact, this is the main (sole?) purpose of unnamed namespaces.
Simply re-naming your classes (e.g. fooX and barX) may work for you in practice, but is not a stable solution, because there is no guarantee that these symbol names are not used by some obscure third-party library loaded at link- or run-time (now or at some point in the future).

how to prove that when compile the templates in C++, the compiler create multiple copies and remove the copies when link

how to prove that when that compile the templates in C++, the compiler generates an instantiation in each compilation unit that uses it, then the linker throws away all but one of them[the commond model];
so there are 2 thing we should prove
1. create multiple copies 2.remove the copies when link
we can prove the second one use the code like
////head.h
#ifndef _TEMP_H
#define _TEMP_H
#include <typeinfo>
#include <iostream>
template<typename T>
class Test
{
public:
Test(T i = 0) : val(i) {}
void getId() const
{
std::cout << typeid(*this).name() << std::endl;
}
void getVal() const
{
std::cout << "Val: " << val << std::endl;
}
private:
T val;
};
#endif
//a.cpp
#include "head.h"
Test<int> a(1);
//b.cpp
#include "head.h"
extern Test<int> a;
int main()
{
Test<int> b;
a.getId();
b.getId();
a.getVal();
b.getVal();
return 0;
}
compiler: g++ 4.4.1
get the result :
4TestIiE
4TestIiE
Val: 1
Val: 0
So the second one has been proved;
But I can not prove the first one
I google it and have some sugestions as followed
1. use the dump yes we can dump the objfile and get the result
but can we write some code to output something to prove it??
Number 1 is easy. Just create a bunch of different source files and include the template header in each one, and use the template class to produce some output. Then compile each source file separately. Now link them each one by one with a main program that calls it. If you don't get any linker errors but the program generates the output, that proves each compiled object file contained the template code.
P.S. The extra copies might not get eliminated, they may still exist as dead code in the executable.
Some compilers definitely don't do that. The IBM C++ compiler generates required templates at link time and compiles them then, in a repeat-until-closure process.

Inline constructors and One Definition Rule

Consider following source files
1.cpp
#include <iostream>
using namespace std;
struct X
{
X()
{
cout << "1" << endl;
}
};
void bar();
void foo()
{
X x;
}
int main()
{
foo();
bar();
return 0;
}
2.cpp
#include <cstdio>
struct X
{
X()
{
printf("2\n");
}
};
void bar()
{
X x;
}
Is program compiled from these files well-formed? What should be in it's output?
I've expected linker error due to violation of One Definition Rule or output "1 2". However it prints out "1 1" when compiled with g++ 3.4 and VC 8.0.
How this can be explained?
This does violate ODR (3.2) - specifically that you can have more than one definition of an inline function, but those definitions must be identical (3.2/5) - and leads to undefined behavior, so anything may happen and the compiler/linker is not required to diagnose that. The most likely reason why you see that behavior is that function calls are inlined and do not participate in linking, so no link error is emitted.
It is undefined behaviour (with no required diagnostic) if inlined functions (such as your class constructor) have different definitions in different translation units.