匿名namespaceによるC++での重複定義の問題の解決

3846 ワード

匿名namespaceによるC++での重複定義の問題の解決
作者:leoxiang日付:2011/11/21
コメントを発表(0)
コメントの表示
今日コードを書く時またC++の中で多くユニットをコンパイルして繰り返し定義(multi definition)のリンクの問題にぶつかりました.実はこの問題は以前にも何度かあったが、コードを急いでコンパイルしても背後の知識を深く研究していない.今日システム的にいくつかの資料を見て、この問題を徹底的に明らかにした.ここで簡単にまとめましょう.
C++にはテンプレート分離コンパイルなどの問題があり,ヘッダファイルに変数定義や関数定義を加える必要があるコードを味わい,マルチコンパイルユニットをリンクする際にmulti-definitionが繰り返し定義する問題がある.
従来のC言語のstaticキーは、C++でクラスのメンバーに対して他の意味を持ち、その機能の限界をもたらす.
C++では匿名namespaceクラスを使用して、multi-definitionの問題を回避するために、関数または変数の定義を1つのコンパイルユニットに限定することを推奨します.
C++では,オブジェクト向けの概念が導入されているため,ヘッダファイルに関数実装や変数定義のコードを加えざるを得ない場合がある.例えば、ほとんどのコンパイラではテンプレート分離コンパイルがサポートされていないため、多くのテンプレートクラスの実装はヘッダファイルにのみ配置され、boostなどのライブラリではhppというフォーマットで完全なヘッダファイル化を実現するライブラリが大量に採用されている.
しかし、この方法はmulti-definitionの繰り返し定義を招き、大規模な工事では多くのコンパイルユニットの形式で複数を生成することが多い.oファイルをldリンクで実行可能ファイルを生成します.複数の場合oには同じhppファイルがincludeされていますが、このhppファイルにはグローバル変数、クラスの静的メンバーなどの変数の定義が含まれており、gccのmulti-definitionエラーが発生します.従来のCプログラムでは、変数または関数がグローバルシンボルを生成しないことをstaticで宣言することでこの問題を解決することができるが、C++のstaticキーワードはクラスのメンバーに対して他の意味を持つ.したがってC++ではstaticの代わりに匿名namespaceを使用してmulti-definitionの問題を回避することを推奨します.次の例を示します.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 ----------- test.hpp---------- #include <string> class A { public :      static std::string y; }; std::string A::y = std::string();
  ----------- test_comm.cpp---------- #include "test.hpp" void func() { }
  ----------- test_main.cpp---------- #include "test.hpp" void func(); int main( int argc, char *argv) {      func(); }
g++でコンパイルすると、次のエラーが発生します.
?
1
2
3
4
5
6 leoxiang@SEC38_64_sles10:~$ g++ -c test_comm.cpp leoxiang@SEC38_64_sles10:~$ g++ -c test_main.cpp leoxiang@SEC38_64_sles10:~$ g++ -o test test_comm.o test_main.o test_main.o:(.bss+0x0): multiple definition of `A::y' test_comm.o:(.bss+0x0): first defined here collect2: ld returned 1 exit status
匿名namespaceでこの問題を解決するにはtestだけだ.hppの実装は匿名namespaceで囲まれており、重複定義の問題を回避することができる.
?
1
2
3
4
5
6
7
8
9
10 ----------- test.hpp---------- #include <string> namespace { class A { public :      static std::string y; }; std::string A::y = std::string(); }
実際に匿名namespaceの役割は,変数をランダムな名前空間に配置し,名前変更空間が複数のコンパイルユニットで一意であることを保証することである.匿名namespaceで宣言または定義された変数関数はグローバルに表示されるため、自分のファイルのコンパイルに影響を与えることはありません.これは、以前のC言語でstaticキーワードの役割を実現し、より実用性が高いことです.
しかし匿名namespaceも完璧ではありません.次の記事「C++エンジニアリング実践(1):匿名namespaceの使用を慎む」では、匿名namespaceの使用による2つの問題を紹介します.
その中の関数はブレークポイントを設定するのが難しく、私のようにgdbのようなテキストモードdebuggerを使用している場合は.
一部のバージョンのg++を使用すると、同じファイルがコンパイルされるたびにバイナリファイルが変化し、一部のbuild toolが機能しなくなります.
同時に、ヘッダファイルで匿名空間を使用すると、ライブラリの使用にいくつかのトラップが発生します.これは、Cでヘッダファイルで静的変数を使用するのと同じです.
それでも、Google C++プログラミング仕様2.1節では、C言語のstaticキーワードの代わりにnamespaceを使用することを奨励しています.したがって、個人的には、ヘッダファイルにクラス静的変数または関数を定義する必要がある場合、ファイルコード全体を匿名namespaceで包むことを考慮すると、重複定義の問題をよりよく解決することができると思います.