After reading static variables in an inlined function, I wrote this test program:
main.cpp:
#include <iostream>
#include "a.h"
#include "f.h"
void g();
int main()
{
std::cout << "int main()\n";
f().info();
g();
}
a.h:
struct A
{
A() { std::cout << "A::A()\n"; }
void info() { std::cout << this << '\n'; }
};
f.h: (singleton local to each compilation unit because of the unnamed namespace)
namespace {
inline A& f()
{
static A x;
return x;
}
}
g.cpp:
#include <iostream>
#include "a.h"
#include "f.h"
void g()
{
std::cout << "void g()\n";
f().info();
}
The problem is that I don't get the same results with different compilers:
g++ 4.8.2: OK
int main()
A::A()
0x6014e8
void g()
A::A()
0x6014d0
clang++ 3.7.0: OK
int main()
A::A()
0x6015d1
void g()
A::A()
0x6015c1
icpc 15.0.2: no call to A::A() inside g() !
int main()
A::A()
0x601624
void g()
0x601620
Is this a bug in icpc ? Is the behaviour of the program not defined ? If I replace "namespace {...}" with "static" in f.h, A::A() is called inside g() as expected. Shouldn't the behaviour be the same?
If I remove "namespace {...}" in f.h, A::info() prints the same object address in main() and g(), and A::A() is called only once (with all compilers) as expected.
Since C++11 mandates names in unnamed namespaces to have internal linkage, every translation unit should have it's own version of f() and, as a result, it's own version of static A x. So gcc and clang are correct.
Seems like icpc is not following C++11 standard and instead following C++03, which allowed those names to be declared with external linkage. Since when you explicitly make f() internal by using static icpc follows the suit, I have a strong suspicion this is simply a bug.
Related
Are odr violations allowed with default gcc( g++, 5.4) options?
For e.g. following code
ODRTest.h
static int x = 0;
inline void odr_violates() {
++x;
std::cout << x << "\n";
}
void g();
void f();
ODRTest1.cpp
#include "ODRTest.h"
void g() { odr_violates();}
ODRTest2.cpp
#include "ODRTest.h"
void f() { odr_violates() ;}
main.cpp
#include "ODRTest.h"
int main() {
f();
g();
}
As x is static, the inline function odr_violates end up changing the static x defined in ODRTest1.cpp and ODRTest2.cpp. Isn't this a violation of ODR - one declaration and two definitions?
Following code also compiles
main.cpp
extern int q;
int main() {
std::cout << q << "\n";
}
ODRTest3.cpp
double q = 1.5;
q always gets printed as 0, is this usage an UB?
Is there an option in GCC that warns or errors out on these obvious ODR violations?
Thanks,
DDG
I've tested the seemingly strange code example below with the newest gcc, clang, and MSVC; both clang and gcc give link errors, but MSVC compiles and links without any problem. Which one is correct?
// foo.h
#pragma once
namespace A
{
class foo
{
public:
foo();
void print();
};
}
// foo.cpp
#include <iostream>
#include "foo.h"
int* p = nullptr;
using namespace A;
foo::foo()
{
p = new int(5);
}
void foo::print()
{
extern int* p;
std::cout << *p;
}
#include "foo.h"
int main()
{
A::foo f;
f.print();
}
gcc and clang:
foo.cpp:(.text+0x35): undefined reference to 'A::p'
Both GCC and Clang are standard compliant. The example and explanation are given in the standard [basic.namespace]/4:
The enclosing namespaces of a declaration are those namespaces in which the declaration lexically appears, except for a redeclaration of a namespace member outside its original namespace (e.g., a definition as specified in [namespace.memdef]). Such a redeclaration has the same enclosing namespaces as the original declaration.
[ Example:
namespace Q {
namespace V {
void f(); // enclosing namespaces are the global namespace, Q, and Q::V
class C { void m(); };
}
void V::f() { // enclosing namespaces are the global namespace, Q, and Q::V
extern void h(); // ... so this declares Q::V::h
}
void V::C::m() { // enclosing namespaces are the global namespace, Q, and Q::V
}
}
— end example]
I have the following:
//a.cpp
inline int f(int x) { return x; }
int g(int x) { return f(x); }
//b.cpp
#include <iostream>
inline int f(int x) { return x + 1; }
extern int g(int);
int main() {
std::cout << g(2) << f(2) << std::endl;
}
The output is 22 (MSVC and GCC), that is, a.cpp f function is been inlined instead of b.cpp one. What's the criteria to choose the f function in this case?
Your code is ill-formed, no diagnostic required. All inline function definitions need to be the same in all translations units.
Since you do not do that the code is ill-formed, but it is allowed to compile and it is not required to cause any sort of warning or error.
You break ODR (One Definition Rule) here and have ill formed program, no diagnostic required.
Each inline definition should be identical.
I'm studying the C++03 Standard and am now reading [7.3.3]/11, but I'm having trouble understanding the following passage:
If a function declaration in namespace scope or block scope has the same name and the same parameter
types as a function introduced by a using-declaration, and the declarations do not declare the same function,
the program is ill-formed.
I haven't found any examples of this situation anywhere and I don't understand the meaning of this passage.
What it means is that:
namespace namespace_1
{
void foo(int number);
}
using namespace_1::foo;
void foo(int roll_no);
This means the program is ill-formed.
I believe it means to say that the function would be confusing to read. As at one point, the function definition would be using the passed int as an integer(general) but in the other case, we'd be using it as a roll_no.
This would also cause ambiguity in overloaded function matching.
The source you are citing gives an example just below the lines you have cited:
namespace B {
void f(int);
void f(double);
}
namespace C {
void f(int);
void f(double);
void f(char);
}
void h() {
using B::f; // B::f(int) and B::f(double)
using C::f; // C::f(int), C::f(double), and C::f(char)
f('h'); // calls C::f(char)
f(1); // error: ambiguous: B::f(int) or C::f(int)?
void f(int); // error: f(int) conflicts with C::f(int) and B::f(int)
}
The following program contains the error
#include <iostream>
namespace _1{
int f(){
std::cout << "_1::f\n";
}
}
namespace _2{
/*
*If a function declaration in namespace scope or block scope has the
*same name and the same parameter types as a function introduced by
* a using-declaration
*/
using _1::f;
// This is not the same function as introduced by the using directive
int f(){
std::cout << "_2::f\n";
}
}
int main(){
_2::f();
}
The diagnostic is
main.cpp: In function ‘int _2::f()’:
main.cpp:13:11: error: ‘int _2::f()’ conflicts with a previous declaration
int f(){
As a contrast, the following program is correct. The _1 namespace is introduced via a using directive.
#include <iostream>
namespace _1{
int f(){
std::cout << "_1::f\n";
}
}
namespace _2{
using namespace _1;
int f(){
std::cout << "_2::f\n";
}
}
int main(){
_2::f();
}
With the expected output
_2::f
As for the same situation in block scope you have
#include <iostream>
namespace _1{
int f(){
std::cout << "_1::f\n";
}
}
namespace _2{
int g(){
// As before but in block scope.
using _1::f;
int f();
f();
}
int f(){
std::cout << "_2::f\n";
}
}
int main(){
_2::f();
}
The diagnostic is identical
main.cpp: In function ‘int _2::g()’:
main.cpp:15:15: error: ‘int _2::f()’ conflicts with a previous declaration
int f();
^
The parallel construct of the successful sample above would be
#include <iostream>
namespace _1{
int f(){
std::cout << "_1::f\n";
}
}
namespace _2{
int g(){
using namespace _1;
int f();
f();
}
int f(){
std::cout << "_2::f\n";
}
}
int main(){
_2::g();
}
With the output
_2::f
Following code do not violate One Definition Rule, yet it is giving an unexpected result:
Test.hpp
class Test
{
public:
int test();
};
Test1.cpp
#include "Test.hpp"
int Test::test()
{
return 1;
}
int test1() // expected to return 1
{
Test a = Test();
return a.test();
}
Test2.cpp
#include "Test.hpp"
inline int Test::test() // doesn't violate ODR
{
return 99;
}
int test2() // expected to return 99
{
Test a = Test();
return a.test();
}
main.cpp
#include <iostream>
int test1();
int test2();
int main()
{
std::cout << test1() << std::endl;
std::cout << test2() << std::endl;
}
I am expecting it to print "1 99", but it always prints "1 1".
Regarding two definitions of Test::test, since one of them is an inline definition, it does not violate One Definition Rule as well.
So this program is valid, but it is not printing out expected result...
Is there anything wrong with this program? Or am I misunderstanding something about ODR rule? (a reference to C++ standard would be helpful).
You are not allowed to define the function as both inline and non-inline.
If a function with external linkage is
declared inline in one translation unit, it shall be declared inline in all translation units in which it appears;
no diagnostic is required.
([dcl.fct.spec]/4)