2011-07-12 17 views
0
私はジェームズCoplienによって「高度なC++プログラミングスタイルとイディオムという名前のいくつかの権威ある本を読んだ後

静的ライブラリの場合は、参照されていない静的オブジェクトは作成されませんか?

、CMAKEを環境GNU GCC(G ++)4.1.2の開発(私は、この本はかなり古いであることを認めなければならない。あなたのため、一部の私は、Exemplarイディオムが継承クラス階層間の依存関係を損なうのに非常に有用であることを発見しました。次のように、このイディオムを扱うための簡単なプロジェクトを作成しようとしました。

あらかじめご了承いただき、ありがとうございます。ソースコード全体を次のように記載しています。 base.cppでbase.h

#ifndef BASE_H_ 
#define BASE_H_ 

#include <string> 

class Exemplar; 

class Base 
{ 
public: 
    Base(Exemplar /* no use */); 
    Base(); 

    virtual Base* make(const std::string& key); 

    virtual void memberMethod1(); 
    virtual int  memberMethod2(); 

    virtual ~Base() {}; 
protected: 
    static Base* list_; 
    Base* next_; 

}; 

#else 
#endif // BASE_H_ 

でexemplar.h

#ifndef EXEMPLAR_H_ 
#define EXEMPLAR_H_ 

class Exemplar 
{ 
public: 
    Exemplar() {}; 
}; 

#else 
#endif // EXEMPLAR_H_ 

でCMakeLists.txt

cmake_minimum_required(VERSION 2.6) 

project(TestProject) 

add_library(exemplar_idiom STATIC base.cpp derived1.cpp) 

add_executable(exemplar_example main.cpp) 
target_link_libraries(exemplar_example exemplar_idiom) 
set_target_properties(exemplar_example PROPERTIES OUTPUT_NAME exemplar_example) 

#include <string> 
#include <iostream> 

#include "exemplar.h" 
#include "base.h" 

Base* Base::list_ = 0; 
static Exemplar exemplar; 
static Base baseInstance(exemplar); 
Base* baseExemplar = &baseInstance; 

Base::Base(Exemplar /* no use */) : next_(list_) 
{ 
    std::cout << "Base object exemplar ctor" << std::endl; 
    list_ = this; 
} 

Base::Base() : next_(0) {} 

Base* Base::make(const std::string& key) 
{ 
    Base* retval = 0; 

    for (Base* a = list_; a; a = a->next_) 
    { 
     if (a != baseExemplar) 
     { 
      if ((retval = a->make(key))) 
      { 
       break; 
      } 
     } 
     else if (key == "base") 
     { 
      retval = new Base(); 
      break; 
     } 
    } 
    return retval; 
} 

void Base::memberMethod1() 
{ 
    std::cout << "base class memberMethod1() called." << std::endl; 
} 

int Base::memberMethod2() 
{ 
    std::cout << "base class memberMethod2() called." << std::endl; 
    return 0; 
} 
main.cppに

#include "base.h" 

extern Base* baseExemplar; 

int main() 
{ 
    Base *ptr = baseExemplar->make("derived1"); 
    if (ptr) { 
     ptr->memberMethod1(); 
     ptr->memberMethod2(); 
    } 

    Base *ptr2 = baseExemplar->make("base"); 
    if (ptr2) { 
     ptr2->memberMethod1(); 
     ptr2->memberMethod2(); 
    } 

    return 0; 
} 

でderived1.h derived1.cpp

#include <iostream> 

#include "exemplar.h" 
#include "derived1.h" 

static Exemplar exemplar; 
static Derived1 derived1Exemplar(exemplar); 

Derived1::Derived1(Exemplar a) : Base(a) 
{ 
    std::cout << "Derived object exemplar ctor" << std::endl; 
} 

Derived1::Derived1() : Base() {} 

Derived1* Derived1::make(const std::string& key) 
{ 
    Derived1* retval = 0; 
    if (key == "derived1") 
    { 
     retval = new Derived1(); 
    } 
    return retval; 
} 

void Derived1::memberMethod1() 
{ 
    std::cout << "Derived1::memberMethod1" << std::endl; 
} 

int Derived1::memberMethod2() 
{ 
    /* dummy */ 
    std::cout << "Derived1::memberMethod2" << std::endl; 
    return 0; 
} 

#include "base.h" 

#ifndef DERIVED1_H_ 
#define DERIVED1_H_ 

class Exemplar; 

class Derived1 : public Base 
{ 
public: 
    Derived1(Exemplar /* no use */); 

    // Conventional default constructor which will be used to instantiate normal object 
    Derived1(); 

    virtual Derived1* make(const std::string& key); 
    virtual void memberMethod1(); 
    virtual int  memberMethod2(); 
}; 

#else 
#endif // DERIVED1_H_ 

我々は少し代入することにより、共有オブジェクトを作成するために、CMakeLists.txtを変更キーワード 'STATIC'を 'SHARED'とすると、私は期待した動作を見ることができました。私は、(Exemplar argを使って)Derived1クラスオブジェクトの静的オブジェクト作成の結果、Baseクラスのリンクリストチェーンが適切に維持されていることが分かりました。その後、main()の基本オブジェクトから仮想make()メソッドを呼び出すと、Derived1オブジェクトとBaseオブジェクトの両方が "derived1"と "base"というキーストリングを指定することによって正常に作成されたことがわかりました。

ただし、「SHARED」というキーワードを「STATIC」に戻すと、別の結果が表示されます。このような静的オブジェクト(Derived1のExampleオブジェクト)はまったく作成されていないようです。そのため、make( "derived1")メンバーメソッドを呼び出すことによってDerived1オブジェクトの作成に失敗しました。

スタティックライブラリの場合でもこの問題を回避する方法はありますか?私は静的オブジェクトコンストラクタの副作用がBaseクラスのリンクリストに期待したいと思います。

ここで私がしようとしていることがあなたに合っているかどうかは確かではありません。しかし、あなたが私に上記のポインタを与えることができれば非常に感謝します。

答えて

1

はい、GNUリンカーldは、実際に使用されていると思われるシンボルのみを追加します。 ldは、シンボルが使用中であるかどうかのみ確認できますが、シンボルの初期化の副作用が使用されているかどうかは確認できません。

このように、未使用の静的オブジェクトが初期化されていないため、結果があなたのような状況になります。

リンクするときに--whole-archiveを使用すると、リンカにすべての記号を含めるように指示できます。欠点は、使用したくないシンボルも追加され、コードサイズが増加することです。

も注意すべきもう一つの事は次のとおりです。

リンカは、彼らがライブラリーからである場合にのみ使用されていないオブジェクトファイルを削除します。リンカーに明示的に渡されたオブジェクトファイルは常にリンクされます。

+0

ありがとうございました。私が上記のポイントに従って何が起こるかを見ると、私は期待したものの正しい振る舞いを見ることができました。 – Smg

関連する問題