ベクトルを扱うクラスを作りたい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
kddoi
記事: 6
登録日時: 11年前

ベクトルを扱うクラスを作りたい

#1

投稿記事 by kddoi » 11年前

はじめまして。表題の通り、ベクトルを扱って計算をさせるクラスをC++で
作ろうとしております。プログラム歴は短くはないですが、本格的に
開発している期間はそれ程長くないので、1~2年くらいに相当すると思います。
データを一つのクラスとして扱い、組み込みのintやdoubleなど型と同じ
ような感覚で扱えるようなものを作りたいと思っております。
よってプログラム自体は込み入ったものになっておりますが、できるだけ
容易に理解していただけるよう単純化しており、あまり意味のないコードに
なっておりますが、必要でしたらさらに詳しく説明いたします。
(実際には以下のコードのクラスがさらに内部にクラスを持っており、
その内部のクラスに参照カウンタを持たせており、参照カウンタが0よりも
大きい間はdeleteされずに残るようになっております)

最初はVisualStudio2010で開発していたのですが、C++11のthreadを使いたい
こともあり、g++ (tmd64-2) 4.8.1をWindows 7 x64上で使っております。
VisualStudioですとビルドが通っていたのですが、g++ではコンパイルが
通りません。プログラムは以下の通りです。

コード:

#include <iostream>
#include <cstdlib>

using namespace std;

class Object{
public:
    Object(void){
        m_length=0;
        m_pData=NULL;
    }
    Object(int length){
        m_length=length;
        m_pData=malloc(length*sizeof(double));
    }
    Object(Object &obj){
        if(m_length!=obj.m_length){
            m_length=obj.m_length;
            free(m_pData);
            m_pData=malloc(m_length*sizeof(double));
        }
        memcpy(this->m_pData, obj.m_pData, m_length*sizeof(double));
    }
    ~Object(){
        free(m_pData);
    }
    Object MakeTmp(void){
        Object tmp(1);
        return tmp;
    }
    Object &operator=(Object &val){
        if(m_length!=val.m_length){
            m_length=val.m_length;
            free(m_pData);
            m_pData=malloc(m_length*sizeof(double));
        }
        memcpy(this->m_pData, val.m_pData, m_length*sizeof(double));
        return *this;
    }
    void Print(void){
        cout << m_length << endl;
    };
private:
    int m_length;
    void *m_pData;
};

int main(void){
    Object obj=Object(1);
    Object obj2=obj.MakeTmp();
    obj.Print();
}

これをコンパイルしようとすると、以下のようなエラーが出ます。

test.cpp:51:24: error: no matching function for call to 'Object::Object(Object)'
Object obj=Object(1);
^
test.cpp:51:24: note: candidates are:
test.cpp:18:5: note: Object::Object(Object&)
Object(Object &obj){
^
test.cpp:18:5: note: no known conversion for argument 1 from 'Object' to 'Object&'
test.cpp:14:5: note: Object::Object(int)
Object(int length){
^
test.cpp:14:5: note: no known conversion for argument 1 from 'Object' to 'int'
test.cpp:9:5: note: Object::Object()
Object(void){
^
test.cpp:9:5: note: candidate expects 0 arguments, 1 provided
test.cpp:52:29: error: no matching function for call to 'Object::Object(Object)'
Object obj2=obj.MakeTmp();
^
test.cpp:52:29: note: candidates are:
test.cpp:18:5: note: Object::Object(Object&)
Object(Object &obj){
^
test.cpp:18:5: note: no known conversion for argument 1 from 'Object' to 'Object&'
test.cpp:14:5: note: Object::Object(int)
Object(int length){
^
test.cpp:14:5: note: no known conversion for argument 1 from 'Object' to 'int'
test.cpp:9:5: note: Object::Object()
Object(void){
^
test.cpp:9:5: note: candidate expects 0 arguments, 1 provided

コピーコンストラクタ(Object(Object &obj))を消せばコンパイルが通るのですが、
今の例ではoperator=とコピーコンストラクタは全く同じコードですが、実際には
違う役割を担っております。operator=の方は、Objectに応じて中身をコピーしたり、
内部オブジェクトのポインタを変更するだけだったり処理を分けております。一方で
コピーコンストラクタでは、値渡しする際にbit単位のコピーが作られてすぐに
デストラクタが呼ばれるので、デストラクタが呼ばれても参照カウンタが狂わないような
調整を行っております。コピーコンストラクタを消せばコンパイルは通るのですが、
両者を両立させる方法はありませんでしょうか?

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: ベクトルを扱うクラスを作りたい

#2

投稿記事 by usao » 11年前

あてずっぽうですが,
コンパイルエラーはこの辺の話が関連してるんじゃないでしょうか
http://q.hatena.ne.jp/1167111891


Object(Object &obj)
Object &operator=(Object &val)
どちらも引数の型を const Object & にしたら解消しませんか?

kddoi
記事: 6
登録日時: 11年前

Re: ベクトルを扱うクラスを作りたい

#3

投稿記事 by kddoi » 11年前

usao さんが書きました:あてずっぽうですが,
コンパイルエラーはこの辺の話が関連してるんじゃないでしょうか
http://q.hatena.ne.jp/1167111891


Object(Object &obj)
Object &operator=(Object &val)
どちらも引数の型を const Object & にしたら解消しませんか?
usao様

さっそくありがとうございました。まさにその通りで、constを付けることでコンパイルが
通るようになりました。以下、少々と細かい話になりますが、
最初はconstを付けていたのですが、operator=の関数内では代入される側(左辺)が、
代入する側(右辺)と同じデータ領域を保持するオブジェクトを差すようにするのみ
(ポインタの値の書き換えのみ)で、実際のデータコピーなどは必要になった際に
初めて行う、という処理にしております。よって必要になった際にデータ領域オブジェクトの
コピーなどを行っておりますので、双方のオブジェクトがお互いのポインタを保持する
必要があり、代入する側(右辺)の中身もいじらなければなりませんでした。今回、
引数にはconstを付けて、関数内部でひたすらconst_castで取り外す、というあまり推奨されない
と思われる実装で対処いたいました。VisualStudioの方は、何も言わずに通してくれるのに、
GNUのコンパイラは厳しいんだな、と思いました。何よりも、エラーメッセージが私のような、
経験が浅いものにとっては、解決の糸口すら掴むのに苦労いたしました。せめて、
教えていただいた参考ウェブサイトにあるように、エラーメッセージに「non-const」の
キーワードさえコンパイラが出してくれれば、と思うところです。
一人ではどうしようもなく、お蔭様で本当に助かりました。ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る