a wandering wolf

Does a wandering wolf dreams of a wondering, sometimes programming sheep?

このエントリーをはてなブックマークに追加

static なメンバ変数のせいでリンクエラーになった話

C++ を書いていて、初心者なのでいろんなことにつまづきます。先日も、リンクエラーに2時間ほど苦しめられていました。

以下がサンプルコードです。コードはあくまでサンプルなので気になさらず。

// MyModule.h
#include <list>

class MyModule {
public:
    static void push(int value);
    static int pop();
private:
    static std::list<int> store;
};

// MyModule.cpp
#include "stdafx.h"
#include "MyModule.h"

void MyModule::push(int value) {
    MyModule::store.push_back(value);
}

int MyModule::pop() {
    std::list<int>::iterator iter = MyModule::store.begin();
    if (iter != MyModule::store.end()) {
        int value = *iter;
        MyModule::store.pop_front();
        return value;
    } else
        return 0;
}

// EntryPoint.cpp
#include "stdafx.h"
#include "MyModule.h"
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
    MyModule::push(1);
    MyModule::push(2);
    MyModule::push(3);

    std::cout << MyModule::pop() << std::endl;
    std::cout << MyModule::pop() << std::endl;
    std::cout << MyModule::pop() << std::endl;

    return 0;
}

これをビルドしようとすると、コンパイルは通るのですが、リンクに失敗します。

MyModule.obj : error LNK2001: 外部シンボル ""private: static class std::list<int,class std::allocator<int> > MyModule::store" (?store@MyModule@@0V?$list@HV?$allocator@H@std@@@std@@A)" は未解決です。

コンパイルが通らないなら何とか自力で追いかけようという気にもなるんですが、リンクに失敗してしまうと何がいけないのか情弱な私には分かりません。(だってコンパイルは通ってるんだぞ!)指摘されている static なメンバ変数 store を private を public に変えてみても、事態は一向に改善されません。

実際のコードはもっと複雑だったので、ぐぐる先生にいろいろ質問しながら2時間ぐらい頑張っていたところで、次の記事を見つけました。

error LNK2001: unresolved external symbol “private: static class - Stack Overflow

どうも、const でない static なメンバ変数は、クラス外で定義しないといけないとのこと。

次のようにコードを修正することで、リンクに成功してビルドが完了します。

// MyModule.cpp
#include "stdafx.h"
#include "MyModule.h"

std::list<int> MyModule::store;  // added

void MyModule::push(int value) {
    MyModule::store.push_back(value);
}

int MyModule::pop() {
    std::list<int>::iterator iter = MyModule::store.begin();
    if (iter != MyModule::store.end()) {
        int value = *iter;
        MyModule::store.pop_front();
        return value;
    } else
        return 0;
}

C++ は難しい…。