携帯を毎朝フル充電しているにも関わらず、会社に着くまでには電池残量不足で電源が切れます。
電車内ではiチャネルでニュース見てるだけなんですけど、数ページ見ただけで残量が減っていき、一瞬で電池残量不足になります。全く使い物になりませぬ!
電池パックを取り出して見るとお餅のように丸くなっています。電池パックのあまりの丸さに、裏の蓋もなかなか閉まらないくらいです。こりゃもう寿命だなー。
(説明は後述) コードとVC++ のプロジェクトファイルを固めたものへのリンク。
C++ の超有名ライブラリboostに、デフォルトのコピー操作をコンパイル時点でエラーにしてくれるboost::noncopyableという便利クラスがあります。
C++ ではコピー操作(コピーコンストラクタやoperator=)が未定義のクラスでコピー操作を行うと、デフォルトのコピーが働きます。しかしポインタをコピーしてしまうなど、デフォルトのコピーでは困るケースがあります。boost::noncopyableを使うと、気づかないうちに意図しないコピーを使っていないかどうかを、コンパイル段階で検出できるのです。便利でしょ。
前置きが長くなりましたが、私もこれはいいなと思って使ってみたのですが、g++ 4.3.2では何も言われないのに、VC++ 2010だとエラーになってしまい困っています。
私の使い方が何か間違っているだけかもしれませんが、同じコードをコンパイルしてもg++ 4.3.2は何も言いません。しかもVC++ 2010の出すエラーメッセージが意味不明すぎてどこをどう直せばいいのかわからんのです…。
コピーOKなクラスAと、コピーNGな(Uncopyable(※1)を継承)クラスBを多重継承した、クラスCを定義(※2)します。このオブジェクトを例外で投げる(main() のthrow C(); の部分)ということがしたいのです。
その際g++ 4.3.2は何も言わないし、できた実行ファイルも正常に動作もしますが、VC++ 2010は「そんなことはできねーよ!」とお怒りになり、コンパイルエラーにされてしまいます。
A <-----------------+-- C
Uncopyable <-- B <--'
しかし、クラスBを取っ払って、下記のように多重継承したクラスDを使うとVC++ も文句を言わなくなります。
A <-----------------+-- D
Uncopyable <--------'
(※)Uncopyableクラスは、boost::noncopyableのコピペにデバッグメッセージを追加しただけのクラスです。
(※2)コピーOKとコピーNGを多重継承するなんて、コピーOKなのかNGなのか矛盾してますよ、テメーの設計はおかしいですよ。という突っ込みはその通りなのですが、今は設計の話ではないので無視して進めてます。
コードは下記の通りです。先頭の #define USE_CLASS_Cを有効にするとパターン1、コメントアウトなどして無効にするとパターン2となります。
#include <iostream>
#include <cstdio>
//#define USE_CLASS_C
class Uncopyable {
protected:
Uncopyable() {
std::cout << "Uncopyable::Uncopyable()" << std::endl;
}
~Uncopyable() throw() {
std::cout << "Uncopyable::~Uncopyable()" << std::endl;
}
private:
Uncopyable(const Uncopyable&);
const Uncopyable& operator=(const Uncopyable&);
};
class A {
public:
A() {
std::cout << "A::A()" << std::endl;
}
virtual ~A() {
std::cout << "A::~A()" << std::endl;
}
virtual const char *func() {
return "A";
}
};
class B : private Uncopyable {
public:
B() {
std::cout << "B::B()" << std::endl;
}
virtual ~B() {
std::cout << "B::~B()" << std::endl;
}
};
#ifdef USE_CLASS_C
class C : public A, public B {
public:
C() : A(), B() {
std::cout << "C::C()" << std::endl;
}
virtual ~C() {
std::cout << "C::~C()" << std::endl;
}
C(const C& c) : A(), B() {
std::cout << "C::C(const C& c)" << std::endl;
}
virtual const char *func() {
std::cout << "C::func()" << std::endl;
return "C";
}
};
#else
class D : public A, private Uncopyable {
public:
D() : A(), Uncopyable() {
std::cout << "D::D()" << std::endl;
}
virtual ~D() {
std::cout << "D::~D()" << std::endl;
}
D(const D& d) : A(), Uncopyable() {
std::cout << "D::D(const D&)" << std::endl;
}
virtual const char *func() {
std::cout << "D::func()" << std::endl;
return "D";
}
};
#endif
int main(int argc, char *argv[])
{
try {
std::cout << "try0" << std::endl;
#ifdef USE_CLASS_C
throw C();
#else
throw D();
#endif
} catch (A& e) {
std::cout << "catch0" << std::endl;
std::cout << "---- " << e.func() << std::endl;
}
getchar();
}
コピペするのすら面倒くさい方のために、 コードとVC++ のプロジェクトファイルを固めたものを置きます。全コードの著作権は放棄しますが、Uncopyableクラスはboostライブラリboost::noncopyableの派生物です。
コンパイルと実行結果は下記の通りです。
パターン1 VC++(エラー)、g++(OK)、パターン2 VC++(OK)、g++(OK)の順に、コンパイル結果と、実行結果を連続して掲載しています。
まずはUncopyableを直接継承していないパターン(パターン1)です。VC++ の結果です。
1>------ ビルド開始: プロジェクト: noncopyable, 構成: Debug Win32 ------ 1> a.cpp 1>y:\projects\c\test\test_noncopyable\a.cpp(55): error C2248: 'Uncopyable::Uncopyable' : privateメンバー (クラス 'Uncopyable' で宣言されている) にアクセスできません。 1> y:projectsctesttest_noncopyablea.cpp(17) : 'Uncopyable::Uncopyable' の宣言を確認してください。 1> y:projectsctesttest_noncopyablea.cpp(7) : 'Uncopyable' の宣言を確認してください。 1> コンパイラでのこの診断により関数 'B::B(const B &)' が生成されました。 ========== ビルド: 0正常終了、1失敗、0更新不要、0スキップ ==========
次にg++ の結果です。
$ g++ -Wall -DUSE_CLASS_C a.c -o c.out $ ./c.out try0 A::A() Uncopyable::Uncopyable() B::B() C::C() catch0 C::func() ---- C C::~C() B::~B() Uncopyable::~Uncopyable() A::~A()
次、クラスBを継承ツリーから省いてUncopyableを直接継承しているパターン(パターン2)です。VC++ の結果です。
try0 A::A() Uncopyable::Uncopyable() D::D() catch0 D::func() ---- D A::a = 0 D::~D() Uncopyable::~Uncopyable() A::~A()
次にg++ の結果です。
$ g++ -Wall a.c -o d.out $ ./d.out try0 A::A() Uncopyable::Uncopyable() D::D() catch0 D::func() ---- D D::~D() Uncopyable::~Uncopyable() A::~A()
な、なぜだ…。一体、何が間違っているというのだ…。
< | 2010 | > | ||||
<< | < | 06 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | - | - | - |
合計:
本日: