Ich habe eine Header-Datei, die eine Vorlage mit einer statischen Variablen deklariert und definiert auch sie:Bin ich garantiert nicht von dieser ODR-Verletzung gebissen?
/* my_header.hpp */
#ifndef MY_HEADER_HPP_
#define MY_HEADER_HPP_
#include <cstdio>
template<int n>
struct foo {
static int bar;
static void dump() { printf("%d\n", bar); }
};
template<int n>
int foo<n>::bar;
#endif // MY_HEADER_HPP_
Dieser Header beide enthalten ist, durch main.cpp
und eine gemeinsam genutzte Bibliothek mylib
. Insbesondere enthält mylib_baz.hpp
nur diese Vorlage und deklariert eine Funktion, die eine Spezialisierung der Vorlage ändert.
/* mylib_baz.hpp */
#ifndef MYLIB_BAZ_HPP_
#define MYLIB_BAZ_HPP_
#include "my_header.hpp"
typedef foo<123> mylib_foo;
void init_mylib_foo();
#endif // MYLIB_BAZ_HPP_
und
/* mylib_baz.cpp */
#include "mylib_baz.hpp"
void init_mylib_foo() {
mylib_foo::bar = 123;
mylib_foo::dump();
};
Wenn ich machen mylib.so
(mit mylib_baz.o
), das Symbol für foo<123>::bar
vorhanden ist, und erklärt schwach. Allerdings ist das Symbol für foo<123>::bar
schwach erklärt auch in meinem main.o
:
/* main.cpp */
#include "my_header.hpp"
#include "mylib_baz.hpp"
int main() {
foo<123>::bar = 456;
foo<123>::dump(); /* outputs 456 */
init_mylib_foo(); /* outputs 123 */
foo<123>::dump(); /* outputs 123 -- is this guaranteed? */
}
Es scheint, dass ich eine Definition Regel bin zu verletzen (foo<123>::bar
definiert sowohl in my_header.cpp
und main.cpp
). Sowohl mit g ++ als auch mit clang werden die Symbole jedoch als schwach (oder eindeutig) deklariert, so dass ich nicht davon gebissen werde - alle Zugriffe auf foo<123>::bar
modifizieren dasselbe Objekt.
Frage 1: Ist das ein Zufall (vielleicht arbeitet ODR für statische Mitglieder von Vorlagen anders?) Oder bin ich tatsächlich garantiert dieses Verhalten durch den Standard?
Frage 2: Wie hätte ich das beobachtete Verhalten vorhersagen können? Das heißt, was genau macht der Compiler das Symbol schwach?
Ich denke, der Standard sagt "Es sollte nicht funktionieren", aber Ihr Linker sagt "Es ist OK". Das ODR zu verletzen ist eine schlechte Idee - der Code wird nicht überall funktionieren. In C gibt es eine "gemeinsame Erweiterung", die die Verwendung mehrerer Definitionen ermöglicht (siehe [Wie verwende ich 'extern', um Variablen zwischen Quelldateien in C zu teilen?] (http://stackoverflow.com/questions/1433204/how-doi-i-use-extern-to-share-variables-between-source-files-in-c/) - das Feature ist wirklich eine Eigenschaft des Linker, und es gibt eine gute Chance, dass Ihre C- und C++ - Compiler die Linker-Technologie teilen.) –
Einverstanden! Ich bin mir auch ziemlich sicher, dass das nicht funktionieren sollte, aber ich kann nicht wirklich sagen warum. In meinem Fall könnte (und sollte!) Ich "bar" 'extern' deklariert haben und nur in' mylib_baz.cpp' definiert haben, um dieses Problem zu lösen. Aber ich bin wirklich neugierig, tiefer zu graben und die Gründe für das beobachtete Verhalten zu sehen. – FreenodeForsakeMe
"' foo <123> :: bar' definiert sowohl in my_header.cpp als auch in main.cpp "... Was? Ich sehe es an einem Ort definiert, der keiner der erwähnten ist: 'my_header.hpp'. Das ist eine Definition. – Barry