Static variable in an inline method across compilation units - c++

Consider the following header file Sample.h:
#pragma once
template<typename T> class Sample {
static T Method() {
static T var = T(0);
var++;
return var;
}
};
int U1Test();
int U2Test();
And 2 compilation units, U1.cpp:
#include "Sample.h"
int U1Test() { return Sample<int>::Method(); }
And U2.cpp:
#include "Sample.h"
int U2Test() { return Sample<int>::Method(); }
Then in another unit Main.cpp:
#include "Sample.h"
#include <iostream>
using namespace std;
int main() {
cout << U1Test() << endl;
cout << U2Test() << endl;
return 0;
}
When compiled, it gives me the following output:
1
2
But I'm not sure how the compiler does this, because the method is inline header-only and there is no compilation unit for it. So I would expect each compilation unit (like U1.cpp and U2.cpp) to receive its own copy of var because the method is inlined in that compilation unit.
Is there a subtle change that would make the variable separate in each compilation unit? I'm asking because code like this in a larger program seems to lead to crashes, so perhaps my reproducer is not enough (the reproducer works according to the C++ standard, AFAIK).
The compiler is g++ (conda-forge gcc 10.3.0-16) 10.3.0 on Ubuntu 20.04.

So I would expect each compilation unit (like U1.cpp and U2.cpp) to receive its own copy of var because the method is inlined in that compilation unit.
(The implicit) inline means that there may be multiple copies of the same function, but the linker will ignore all but one of them. Thus, all compilation units access that one function instantiation.
Is there a subtle change that would make the variable separate in each compilation unit?
Yes, make the function (freestanding) static rather than (implicitly) inline:
static T Method() {
static T var = T(0);
var++;
return var;
}
Note that this function is not in a class.

Related

linker error in simple program: multiple definition of function

My function test is added to two different .cpp-files and the functions are private to their respective files as shown below
test1.cpp
#include <iostream>
using namespace std;
void test()
{
cout << "test" << endl;
}
test2.cpp
#include <iostream>
using namespace std;
void test()
{
cout << "test" << endl;
}
main.cpp
#include <iostream>
using namespace std;
int main()
{
return 0;
}
During linking I get the error multiple definition of test() - but how is that possible, considering that the two files have their own private scope!? I could understand it if I included the function prototype in each .cpp-files' corresponding header, but there is no such thing in this example.
You need the inline keyword for that:
inline void test()
{
cout << "test" << endl;
}
This allows you to have multiple definitions in separate source files without violating the one-definition rule. However, note that the function still has external linkage and they will all resolve to the same address. Also:
An inline function shall be defined in every translation unit in which
it is odr-used and shall have exactly the same definition in every
case
If you want separate functions with different addresses (internal linkage), use the static keyword instead.
Both test functions are in the same global namespace of the program. In order to avoid error you may:
1) wrap any or both functions in namespace:
namespace A
{
void test()
{
...
}
}
2) use static keyword
3) just rename one of them
Add static in each test function.
#include <iostream>
using namespace std;
static
void test()
{
cout << "test" << endl;
}
To elaborate on above answers:
In C++, function declarations can be repeated as many times as you want. A function definition however (i.e. the function body), can occur only once.
When creating your binary, the compiler compiles each file to a obj file so in your example you end up with test1.obj, test2.obj and main.obj. After all files compiled successfully, the linker links them together to create your executable. This is where multiple definitions for the same function are found and why linking fails.
Depending on what you want, you can do the following to resolve this:
If you want multiple different functions with the same name, then you have to disambiguate them. C++ wouldn't be C++ if you only had one way to do this:
The old c way: use the static keyword
Use an anonymous namespace
Use a namespace
If you want only one function:
Separate the definition from the declaration, i.e. put the declaration in a header file and move the definition to a source file.
Define the function as inline in a header

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.

How can a type that is used only in one compilation unit, violate the One Definition Rule?

I was told that these types, that are visible in there own unique translation unit, were in violation of the One Definition Rule. Can someone explain this?
//File1.cpp
#include "StdAfx.h"
static struct S { int Value() { return 1; } } s1;
int GetValue1() { return s1.Value(); }
//File2.cpp
#include "StdAfx.h"
static struct S { int Value() { return 2; } } s2;
int GetValue2() { return s2.Value(); }
// main.cpp
#include "stdafx.h"
extern int GetValue1();
extern int GetValue2();
int _tmain(int argc, _TCHAR* argv[])
{
if( GetValue1() != 1 ) throw "ODR violation";
if( GetValue2() != 2 ) throw "ODR violation";
return 0;
}
I know how to fix the problem. As per the title, I was looking to why it was a ODR violation. How does it violate: "In any translation unit, a template, type, function, or object can have no more than one definition."? Or maybe it violates a different part of the rule.
The problem is that, even though s1 and s2 have only internal linkage, both of the corresponding definitions of S have external linkage.
What you want to do is to use an anonymous namespace:
//File1.cpp
#include "StdAfx.h"
namespace {
struct S { int Value() { return 1; } } s1;
}
int GetValue1() { return s1.Value(); }
//File2.cpp
#include "StdAfx.h"
namespace {
struct S { int Value() { return 2; } } s2;
}
int GetValue2() { return s2.Value(); }
Edit:
Everything inside the anonymous namespace, including the class definitions, has internal linkage.
Definitions in the anonymous namespace still have external linkage, but the compiler ensures that they receive unique names that won't clash with any definitions from other translation units.
This is unsafe because you have two structs named S. The static keyword only applies to the variable declaration; it's equivalent to you having written:
struct S {
int Value() {return 1;}
};
static S s1;
The compiler doesn't notice this at compile time because it deals with each translation unit separately. The Value functions in the structs are mangled to exactly the same name, and become weak global symbols in the object files, so the linker doesn't throw an error about a symbol name collision; it just picks one to use in the fully-linked binary. This will probably be the first symbol definition, which means you can actually get different behavior depending on the order you linked the objects:
> g++ -o test test.o test1.o test2.o && ./test
s1 is 1
s2 is 1
> g++ -o test test.o test2.o test1.o && ./test
s1 is 2
s2 is 2
You can get around this by either wrapping the structs in anonymous namespaces (which will make the Value function symbols locals instead of weak globals):
namespace {
struct S {
int Value() {return 1;}
} s1;
}
Or simply removing the name of the struct, since you don't actually need it:
struct {
int Value() {return 1;}
} s1;
You have defined struct S in the global namespace in two different ways, which breaks the One Definition Rule. In particular, there are two different definitions of ::S::Value(), and it's undefined which will actually end up being called.
You should use nameless namespaces to make sure a distinctly named version of struct S is defined in each translation unit:
namespace { struct S {int Value() {return 1;}} s1; }
int GetValue1() {return s1.Value();}
There's a lot more to the One Definition Rule than the first paragraph which you quote. The last paragraph basically says that some things, including class definitions, can appear more than once in a program, as long as they are all identical. Your code breaks this last condition. Or, in the (abridged) words of the Standard:
There can be more than one definition of a class type ... in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then each definition of D shall consist of the same sequence of tokens.

several definitions of the same class

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 ?