mapに自作クラスをinsertしようとすると落ちる

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

mapに自作クラスをinsertしようとすると落ちる

#1

投稿記事 by Rag » 7年前

初めまして、Ragと申します。
mapをメンバとして持つクラスを作ったのですが、mapに自作のクラスをinsertしようとするとプログラムが落ちます。
map<int, string>などは普通にinsertできるので自作クラスに問題があるのではないかと思っていますが、原因が分かりません。
何が原因なのか、追加すべきものがあるのか、ご助力いただければと思います。

開発環境はWindows7(64bit)、VisualStudio 2012です。
作成しているプログラムは以下の通りです。

ID番号付きの2次元の点を表すCPoint2DWithIDを、
2次元の3角形を表すCTriangle2Dに頂点の情報としてmapに格納しようとしています。
コンパイルは通るのですが、プログラムを実行するとinsertのところで動作が停止します。
コードで長くなりますが、よろしくお願い致します。

main.cpp

コード:

#include <stdio.h>
#include "CTriangle2D.h"

int main() {
	CPoint2DWithID *aPoint1 = new CPoint2DWithID(1, 10.0, 10.0);
	CPoint2DWithID *aPoint2 = new CPoint2DWithID(7, 50.0, 10.0);
	CPoint2DWithID *aPoint3 = new CPoint2DWithID(4, 10.0, 30.0);

	CTriangle2D *aTriangle = new CTriangle2D(*aPoint1, *aPoint2, *aPoint3);
	// ここで中のnodesにinsertできずに落ちる

	return 0;
}
CTriangle2D.h

コード:

#ifndef INCLUDE_CTRIANGLE2D
#define INCLUDE_CTRIANGLE2D

#include <map>
#include "CPoint2DWithID.h"

class CTriangle2D {
private:
	std::map<int, CPoint2DWithID> nodes;
public:
	// Constructor
	CTriangle2D(CPoint2DWithID cCPoint2DWithID1, CPoint2DWithID cCPoint2DWithID2, CPoint2DWithID cCPoint2DWithID3);

	// Destructor
	virtual ~CTriangle2D();

	// Functions
	bool equals(CTriangle2D cCTriangle2D);
	bool isInThisTriangle(CPoint2D cCPoint2D);
	bool isInThisTriangle(double cX, double cY);

	// getter
	std::map<int, CPoint2DWithID> getNodes() const;
};

#endif // INCLUDE_CTRIANGLE2D
CTriangle2D.cpp

コード:

#include "CTriangle2D.h"

// Constructor
CTriangle2D::CTriangle2D(CPoint2DWithID cCPoint2DWithID1, CPoint2DWithID cCPoint2DWithID2, CPoint2DWithID cCPoint2DWithID3) {
	// 3角形を構成する3点をnodesに登録する
	this->nodes.insert(std::map<int, CPoint2DWithID>::value_type(cCPoint2DWithID1.getID(), cCPoint2DWithID1));
	this->nodes.insert(std::map<int, CPoint2DWithID>::value_type(cCPoint2DWithID2.getID(), cCPoint2DWithID2));
	this->nodes.insert(std::map<int, CPoint2DWithID>::value_type(cCPoint2DWithID3.getID(), cCPoint2DWithID3));
}

// Destructor
CTriangle2D::~CTriangle2D() {
	// TODO デストラクタの作成
}

// Functions
bool CTriangle2D::equals(CTriangle2D cCTriangle2D) {
	// 要素の3点をそれぞれ取り出し、すべてにおいてequalsであればtrue
	std::map<int, CPoint2DWithID>::iterator aIterator = this->nodes.begin();
	CPoint2DWithID aThisPoint1 = (*aIterator).second;	++aIterator;
	CPoint2DWithID aThisPoint2 = (*aIterator).second;	++aIterator;
	CPoint2DWithID aThisPoint3 = (*aIterator).second;

	aIterator = cCTriangle2D.getNodes().begin();
	CPoint2DWithID aOtherPoint1 = (*aIterator).second;	++aIterator;
	CPoint2DWithID aOtherPoint2 = (*aIterator).second;	++aIterator;
	CPoint2DWithID aOtherPoint3 = (*aIterator).second;

	bool aBool;
	aBool = aThisPoint1.equals(aOtherPoint1);
	if (!aBool) {
		return false;
	}

	aBool = aThisPoint2.equals(aOtherPoint2);
	if (!aBool) {
		return false;
	}

	aBool = aThisPoint3.equals(aOtherPoint3);
	if (!aBool) {
		return false;
	}

	return true;
}

bool CTriangle2D::isInThisTriangle(CPoint2D cCPoint2D) {
	bool aBool = this->isInThisTriangle(cCPoint2D.getX(), cCPoint2D.getY());

	return aBool;
}

bool CTriangle2D::isInThisTriangle(double cX, double cY) {
	// 格納している3点を展開
	std::map<int, CPoint2DWithID>::iterator aIterator = this->nodes.begin();
	CPoint2DWithID aThisPointA = (*aIterator).second;	++aIterator;
	CPoint2DWithID aThisPointB = (*aIterator).second;	++aIterator;
	CPoint2DWithID aThisPointC = (*aIterator).second;

	// 点の値のみに分解
	double aAx = aThisPointA.getPoint2D()->getX();
	double aAy = aThisPointA.getPoint2D()->getY();
	double aBx = aThisPointB.getPoint2D()->getX();
	double aBy = aThisPointB.getPoint2D()->getY();
	double aCx = aThisPointC.getPoint2D()->getX();
	double aCy = aThisPointC.getPoint2D()->getY();
	double aDx = cX;
	double aDy = cY;
	
	// 辺ベクトルと頂点から点Dへのベクトルでそれぞれ外積ベクトルの大きさを求める
	// 外積ベクトル (A→B)×(A→D)
	double aCPVectorABAD = (aBx - aAx) * (aDy - aAy) - (aDx - aAx) * (aBy - aAy);
	// 外積ベクトル (B→C)×(B→D)
	double aCPVectorBCBD = (aCx - aBx) * (aDy - aBy) - (aDx - aBx) * (aCy - aBy);
	// 外積ベクトル (C→A)×(C→D)
	double aCPVectorCACD = (aAx - aCx) * (aDy - aCy) - (aDx - aCx) * (aAy - aCy);

	// 3つの外積ベクトルの値がすべて0以上、もしくは0以下ならこの三角形上に存在する
	// 値の1つが0なら辺上、2つが0なら頂点上に存在する
	if ((aCPVectorABAD >= 0.0 && aCPVectorBCBD >= 0.0 && aCPVectorCACD >= 0.0)
		|| (aCPVectorABAD <= 0.0 && aCPVectorBCBD <= 0.0 && aCPVectorCACD <= 0.0)) {
			return true;
	}

	return false;
}

// Getter
std::map<int, CPoint2DWithID> CTriangle2D::getNodes() const {

	return this->nodes;
}
CPoint2DWithID.h

コード:

#ifndef INCLUDE_CPOINT2DWITHID
#define INCLUDE_CPOINT2DWITHID

#include "CPoint2D.h"

class CPoint2DWithID {
private:
	int id;
	CPoint2D *point2D;
public:
	// Constructor
	CPoint2DWithID();
	CPoint2DWithID(int cID, CPoint2D cCPoint2D);
	CPoint2DWithID(int cID, double cX, double cY);

	// Destructor
	~CPoint2DWithID();

	// Functions
	bool equals(CPoint2DWithID cCPoint2DWithID);
	bool equals(int cID, CPoint2D cCPoint2D);
	bool equals(int cID, double cX, double cY);
	bool equals(CPoint2D cCPoint2D);
	bool equals(double cX, double cY);

	// Getter
	int getID() const;
	CPoint2D *getPoint2D() const;
	
	// Setter
	void setID(int cID);
	void setPoint2D(CPoint2D cCPoint2D);
	void setPoint2D(double cX, double cY);
};

#endif	// INCLUDE_CPOINT2DWITHID
CPoint2DWithID.cpp

コード:

#include "CPoint2DWithID.h"

// Constructor
CPoint2DWithID::CPoint2DWithID() {
	this->id = 0;
	this->point2D = new CPoint2D();
}

CPoint2DWithID::CPoint2DWithID(int cId, CPoint2D cCPoint2D) {
	this->id = cId;
	this->point2D = new CPoint2D(cCPoint2D.getX(), cCPoint2D.getY());
}

CPoint2DWithID::CPoint2DWithID(int cId, double cX, double cY) {
	this->id = cId;
	this->point2D = new CPoint2D(cX, cY);
}

// Destructor
CPoint2DWithID::~CPoint2DWithID() {
	delete this->point2D;
}

// functions
bool CPoint2DWithID::equals(CPoint2DWithID cCPoint2DWithID) {
	bool aBool = this->equals(cCPoint2DWithID.getID(), *cCPoint2DWithID.getPoint2D());

	return aBool;
}

bool CPoint2DWithID::equals(int cId, CPoint2D cCPoint2D) {
	if (this->id != cId) {
		return false;
	}

	bool aBool = this->point2D->equals(cCPoint2D);

	return aBool;
}

bool CPoint2DWithID::equals(int cId, double cX, double cY) {
	if (this->id != cId) {
		return false;
	}

	bool aBool = this->point2D->equals(cX, cY);

	return aBool;
}

bool CPoint2DWithID::equals(CPoint2D cCPoint2D) {
	bool aBool = this->point2D->equals(cCPoint2D);

	return aBool;
}

bool CPoint2DWithID::equals(double cX, double cY) {
	bool aBool = this->point2D->equals(cX, cY);

	return aBool;
}

// Getter
int CPoint2DWithID::getID() const {
	return this->id;
}

CPoint2D *CPoint2DWithID::getPoint2D() const {
	return this->point2D;
}

// Setter
void CPoint2DWithID::setID(int cId) {
	this->id = cId;
}

void CPoint2DWithID::setPoint2D(CPoint2D cCPoint2D) {
	this->point2D->setX(cCPoint2D.getX());
	this->point2D->setY(cCPoint2D.getY());
}

void CPoint2DWithID::setPoint2D(double cX, double cY) {
	this->point2D->setX(cX);
	this->point2D->setY(cY);
}
CPoint2D.h

コード:

#ifndef INCLUDE_CPOINT2D
#define INCLUDE_CPOINT2D

class CPoint2D {
private:
	double x;
	double y;
public:
	// Constructor
	CPoint2D();
	CPoint2D(double cX, double cY);

	// Destructor
	virtual ~CPoint2D();

	// Functions
	bool equals(CPoint2D cCPoint2D);
	bool equals(double cX, double cY);

	// Getter
	double getX() const;
	double getY() const;

	// Setter
	void setX(double cX);
	void setY(double cY);
};

#endif	// INCLUDE_CPOINT2D
CPoint2D.cpp

コード:

#include "CPoint2D.h"

// Constructor
CPoint2D::CPoint2D() {
	this->x = 0.0;
	this->y = 0.0;
}

CPoint2D::CPoint2D(double cX, double cY) {
	this->x = cX;
	this->y = cY;
}

// Destructor
CPoint2D::~CPoint2D() {
}

// Functions
bool CPoint2D::equals(CPoint2D cCPoint2D) {
	bool aBool = this->equals(cCPoint2D.getX(), cCPoint2D.getY());

	return aBool;
}

bool CPoint2D::equals(double cX, double cY) {
	if (this->x != cX) {
		return false;
	}

	if (this->y != cY) {
		return false;
	}

	return true;
}

// Getter
double CPoint2D::getX() const {
	return this->x;
}

double CPoint2D::getY() const {
	return this->y;
}

// Setter
void CPoint2D::setX(double cX) {
	this->x = cX;
}

void CPoint2D::setY(double cY) {
	this->y = cY;
}

アバター
h2so5
副管理人
記事: 2212
登録日時: 9年前
住所: 東京
連絡を取る:

Re: mapに自作クラスをinsertしようとすると落ちる

#2

投稿記事 by h2so5 » 7年前

関数に値をそのまま渡すと(つまり、値渡しをすると)、その値がビット単位でコピーされることになります。実は このとき、非常に大きな問題が起こる可能性があります。もし、渡されたのがクラスのインスタンスで、メンバ変数に ポインタが含まれていたらどうなるでしょう? ポインタもコピーされてしまう訳なので、同じ場所を指すポインタが、 コピー元とコピー先とで2つ存在することになります。同じ場所を指すポインタが複数存在するのは危険なことです。 お互いに間接参照によって、同じ場所を変更し合うことが起こり得るため、データの整合性が保てなくなります。更に、 そのポインタがnew演算子によって確保された領域を指している場合、片方のポインタを使ってdeleteしてしまうと、 もう一方はそのことを知らずに、引き続きその領域をアクセスしようとするかも知れません。もちろん、その領域は解放 済みなので アクセスエラーが発生します。
http://www.geocities.jp/ky_webid/cpp/language/016.html

YuO
記事: 941
登録日時: 9年前
住所: 東京都世田谷区

Re: mapに自作クラスをinsertしようとすると落ちる

#3

投稿記事 by YuO » 7年前

Rag さんが書きました:mapをメンバとして持つクラスを作ったのですが、mapに自作のクラスをinsertしようとするとプログラムが落ちます。
map<int, string>などは普通にinsertできるので自作クラスに問題があるのではないかと思っていますが、原因が分かりません。
それを調べるためにデバッグするのですが……。
Rag さんが書きました:開発環境はWindows7(64bit)、VisualStudio 2012です。
VS2012なら,IDEでソースコードデバッグできるし,落ちる前にIDEが例外を捕らえてくれると思いますが。
ちゃんと,「デバッグ開始」で実行して試しましたか。
Rag さんが書きました:コンパイルは通るのですが、プログラムを実行するとinsertのところで動作が停止します。
STLコンテナの要素は,内部でコピーコンストラクタが使われます。
ポインタメンバを持つならば,std::shared_ptrのようなスマートポインタを使って管理するか,
自分でコピーコンストラクタを書いてコピー可能にしておかなければいけません。

Rag
記事: 8
登録日時: 8年前

Re: mapに自作クラスをinsertしようとすると落ちる

#4

投稿記事 by Rag » 7年前

h2so5さん、YuOさん、回答ありがとうございます。

ポインタメンバを持つクラスを値渡ししようとすると問題が起きるというのは理解できました。
デバッグの使い方については良く分かっていませんでした。
ご指摘いただいたところを調べて直そうと思います。

CPoint2DWithIDは内部でCPoint2Dを持つのではなく、継承で作るべきだったかもしれません。
合わせて作り直してきます。

Rag
記事: 8
登録日時: 8年前

Re: mapに自作クラスをinsertしようとすると落ちる

#5

投稿記事 by Rag » 7年前

教えていただいたコピーコンストラクタによる解決ではありませんが、CPoint2DWithIDをCPoint2Dの継承とすることで一応は解決できました。

閉鎖

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