Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Automatically Implemented Functions and the ODR

Long explanation follows, question at bottom.

My question specifically refers to the current C++ draft standard (but also the current 'main' standard) found here. More specifically, section 3.2 point 6 (page 35) states each definition of D shall consist of the same sequence of tokens, with regard to member functions and the ODR.

I recently encountered the following problem in a project while I was adding a new data analysis.

I was writing a file, A.cpp. I created a small dummy struct to hold some Data. In this example, I will call it Data.

namespace Example {
struct Data {
    //etc
};
//Use Data
};

However in anther file, B.cpp, there was already a struct called Data inside the Example namespace. The compiler generates Data::~Data(); for both classes, which in turn calls the destructors of their respective members. The definition in B.cpp contains a vector, which when destructed caused explosions when called on Data structs using the layout defined in A.cpp. While both structs appear to work correctly, with no compile time errors, it appears that at link time the linker would pick one definition and use that, ignoring the other definition. (Hence caused explosions on Data objects inside of A.cpp)

No warning is issued under GCC or under MSVC. When optimisation is enabled the problem does not occur (the functions are inlined, no link time confusion).

My question is, the standard only states that the behaviour is undefined If D is a template and is defined in more than one translation unit. Either I have misunderstood the standard, and the undefined behaviour is allowed to silently occur; or both GCC and MSVC are silently accepting something they shouldn't (and should either refuse to produce an output or issue a warning) (The current situation is undefined and inconsistent behaviour without a diagnostic).

Could someone please help me understand how this is different to conflicting definitions of functions that are not defined in classes (which do cause warnings/errors).

like image 982
James Avatar asked Oct 21 '22 19:10

James


1 Answers

Could someone please help me understand how this is different to conflicting definitions of functions that are not defined in classes (which do cause warnings/errors).

The difference is that function definitions inside a class are implicitly nominally inline, which inhibits the compiler warnings if the function's encountered again. That doesn't mean the compiler has to inline them - it may decide using whatever heuristics not to bother, or it may simple never inline at some optimisation levels. Anyway, if you link code that's seen different definitions of nominally inline non-member functions you have exactly the same problem.

See 3.2/6

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.

— each definition of D shall consist of the same sequence of tokens; and

[others requirements]

More generally, you should have put your code into anonymous namespaces... they're designed to prevent cross-translation-unit problems of this kind.

like image 188
Tony Delroy Avatar answered Oct 23 '22 17:10

Tony Delroy