listの強化クラスslist作成中。途中経過

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

listの強化クラスslist作成中。途中経過

投稿記事 by MoNoQLoREATOR » 14年前

とりあえず現在はこんな感じ↓

CODE:

#include 
#include 
#include 

template 

class slist :public std::list{
	iterator itBeg;
	iterator itEnd;

public:

	SLIST& operator[] (const int &num){
		iterator it = begin();
		std::advance(it, num);
		return *it;
	}

	//×
	void operator+= (std::list &list){
		merge(list);
	}

	void operator+= (SLIST &ele){
		push_back(ele);
	}

	void operator+= (std::vector &arr){
		for(size_t i=0;i &arr){
		clear();
		for(size_t i=0;i= (const int &num){
		set(num);
	}

	void operator! (void){
		reset();
	}

	SLIST& operator++ (void){
		SLIST iterEle = *itBeg;
		itBeg++;
		return iterEle;
	}

	SLIST& operator-- (void){
		SLIST iterEle = *itEnd;
		itEnd--;
		return iterEle;
	}

	void addArr(const SLIST *arr, const int num){
		for(int i=0;i slst;
	std::list lst;
	slst.addArr(nums, 5);	//slstにnumsのデータを追加
	for(int i=0;i' に対して後置形式でない 'operator ++' が見つかりました。前置形式にします。
        with
        [
            SLIST=int
        ]
c:\documents and settings\administrator\my documents\visual studio 2008\projects\slist\main.cpp(64) : warning C4172: ローカル変数またはテンポラリのアドレスを返します。
        c:\documents and settings\administrator\my documents\visual studio 2008\projects\slist\main.cpp(61): クラス テンプレート のメンバ関数 'int &slist::operator ++(void)' のコンパイル中
        with
        [
            SLIST=int
        ]
        c:\documents and settings\administrator\my documents\visual studio 2008\projects\slist\main.cpp(83) : コンパイルされたクラスの テンプレート のインスタンス化 'slist' の参照を確認してください
        with
        [
            SLIST=int
        ]
リンクしています...
マニフェストを埋め込んでいます...
ビルドログは "file://c:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Projects\slist\Debug\BuildLog.htm" に保存されました。
slist - エラー 0、警告 2
========== ビルド: 1 正常終了、0 失敗、0 更新不要、0 スキップ ==========
という警告が出てしまいます。
83行目というのは
slist slst;
89行目というのは
for(int i=0;i<10;i++) printf("%d\n", slst++); //slstの要素を最初から最後まで表示
のことです。
ためしに89行目を
for(int i=0;i<10;i++) printf("%d\n", ++slst); //slstの要素を最初から最後まで表示
というように、"++"の位置を逆にしてみると、89行目に対する警告はなくなりました。
両方可能にはできないのでしょうか?

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: listの強化クラスslist作成中。途中経過

投稿記事 by MoNoQLoREATOR » 14年前

追記
出力結果は
0011223344
というように、自動的にソートされてしまいました。
push_back()を使用して、かつ自動的にソートさせないようにする方法はないのでしょうか?

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: listの強化クラスslist作成中。途中経過

投稿記事 by MoNoQLoREATOR » 14年前

違いましたね。push_back()ではなくmerge()を使用した際に、連結するリストがソートされていれば連結結果もソートされるのですね。
だから連結するリストがソートされていても連結結果をソートしない関数を別に作ればよいのですね。

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: listの強化クラスslist作成中。途中経過

投稿記事 by MoNoQLoREATOR » 14年前

本家listクラスのmerge()関数について新たな事実を発見しました。

ソート済みリストにソート済みリストを結合・・・問題なし
ソート済みリストに未ソートのリストを結合・・・アプリケーションエラー
未ソートのリストにソート済みリストを結合・・・アプリケーションエラー
未ソートのリストに未ソートのリストを結合・・・アプリケーションエラー

という結果になりました。本家listクラスのmerge()関数は、ソート済みリストにソート済みリストを結合することしかできないようです。

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: listの強化クラスslist作成中。途中経過

投稿記事 by MoNoQLoREATOR » 14年前

前置・後置のインクリメント・デクリメントの問題は解決しました。
別途 定義が必要なのですね。
しかしわかりません。後置式の場合は、古いデータを返す必要があるらしいのですが、何故なのでしょう?
質問掲示板で質問してみることにします。

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: listの強化クラスslist作成中。途中経過

投稿記事 by MoNoQLoREATOR » 14年前

”ローカル変数またはテンポラリのアドレスを返します”
という警告についても、解決しました。クラス直下のメンバ変数に
SLIST iterEle;
を追加し、そこにデータを入れてそのアドレスを返すようにしました。
あとはちゃんと動作するかテストするだけです。
完成の瞬間がぐっと近づいた気がします。

アバター
a5ua
記事: 199
登録日時: 14年前

RE: listの強化クラスslist作成中。途中経過

投稿記事 by a5ua » 14年前

まず、警告の内容ですが、

operator++のオーバーロードについて、

CODE:

SLIST& operator++(void);
これは、前置形式のoperator++となります。
後置形式のoperator++を宣言するには、

CODE:

SLIST& operator++(int);
のように、引数にintを一つ書きます。

それから、

CODE:

SLIST& operator++ (void){
	SLIST iterEle = *itBeg;
	itBeg++;
	return iterEle;
}
このコードにおいて、iterEleは一時オブジェクトであり、このスコープを抜けると破棄されるため、
そのオブジェクトへの参照を返しても、呼び出し元で正しく参照される保証はありません。
修正するとしたら、以下のようになります。

CODE:

SLIST& operator++ (void){
	SLIST &iterEle = *itBeg;
	itBeg++;
	return iterEle;
}

ご自覚されているように、演算子オーバーロード(特に、直感的でないもの)の乱用は
コードを読む人に、混乱を与えます。(しばらくたったら、ご自身でもわからなくなる可能性があります)

CODE:

slst += lst;    //slstにlstのデータを追加
このコードが、データの追加行おうとしていることは分かりますが、
(lstの中身がslstに移動することは想像できませんが…)

CODE:

!slst;  //slstのイテレータを初期化
このコードを見ただけでは、少なくとも私には、処理内容を想像できません。

また、同等の機能をもつメンバ関数が用意されているのであれば、そちらを使うべきだと思います。

CODE:

// リストへの追加や表示のサンプルコード
#include 
#include 
#include 	// std::copy
#include 		// std::ostream_iterator

int main()
{
    int nums[5] = {0, 1, 2, 3, 4};
	std::list list1;
	std::list list2;

	list1.insert(list1.end(), nums, nums + 5);				// numsの内容をlist1の末尾に挿入(ポインタはイテレータの一種である)
	list2.insert(list2.end(), list1.begin(), list1.end());	// list1の内容をlist2の末尾に挿入
	list1.splice(list1.end(), list2);						// list2をlist1の末尾にくっつける(list2は空になる)

	// list1の内容をすべて表示
	std::copy(list1.begin(), list1.end(), std::ostream_iterator(std::cout, "\n"));
}
ヘッダには、イテレータを受け取り、処理を行う関数がいくつも定義されています。
STLをフルに活用するには、これらを使うのが必須であると思うので、勉強されてみてはいかがでしょうか?

アバター
GRAM
記事: 164
登録日時: 14年前

Re: listの強化クラスslist作成中。途中経過

投稿記事 by GRAM » 14年前

僕が思うこととしては、(多くをa5uaさんがおっしゃっていることですが)ややこしいはなしを抜きにすると
constもっと使ったほうがよいのでは? ということです。
メンバ関数にconst修飾子がついていません
引数にもconstがあまりついていません。
もっとconstを付けられえる部分がたくさんあるはずだと思うのですが。

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

RE: listの強化クラスslist作成中。途中経過

投稿記事 by MoNoQLoREATOR » 14年前

>>a5uaさん
おっしゃる通りです。しかし気になる点が少し・・・。
a5ua さんが書きました:

CODE:

SLIST& operator++ (void){
	SLIST iterEle = *itBeg;
	itBeg++;
	return iterEle;
}
このコードにおいて、iterEleは一時オブジェクトであり、このスコープを抜けると破棄されるため、
そのオブジェクトへの参照を返しても、呼び出し元で正しく参照される保証はありません。
修正するとしたら、以下のようになります。

CODE:

SLIST& operator++ (void){
	SLIST &iterEle = *itBeg;
	itBeg++;
	return iterEle;
}
これでは0番目の要素が取り出せなくなってしまうのでは?
a5ua さんが書きました:

CODE:

slst += lst;    //slstにlstのデータを追加
このコードが、データの追加行おうとしていることは分かりますが、
(lstの中身がslstに移動することは想像できませんが…)
push_back()を使用しているので、内部でデータがコピーされ、移動することはないと思うのですが、違うのでしょうか?



※おかしな事書いてたので消しました



>>GRAMさん
そうですね。constをつける習慣をつけないといけませんね。
最後に編集したユーザー MoNoQLoREATOR on 2011年8月07日(日) 16:33 [ 編集 2 回目 ]

アバター
GRAM
記事: 164
登録日時: 14年前

Re: listの強化クラスslist作成中。途中経過

投稿記事 by GRAM » 14年前

a5uaさんがおっしゃっていることは基本的に正当性があります。
もう一度ご自身のコードと提示されたコードを見比べて見ることと、
実際の動作の確認をしてみることをお勧めします。

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: listの強化クラスslist作成中。途中経過

投稿記事 by MoNoQLoREATOR » 14年前

すみません。
何も考えずに思ったことを書いてますね。

CODE:

SLIST& operator++ (void){
    SLIST &iterEle = *itBeg;
    itBeg++;
    return iterEle;
}
このコードで合ってますね。
インクリメントが書いてあったから(自分が書いたんですが^^;)とっさに
=======================
取り出したい値のアドレスを記憶

値をインクリメント

値をインクリメントする前にアドレスを記憶した意味なし
=======================
と思ってしまいました。
イテレーター紛らわしい・・・。

リストが移動する件ですが・・・もしかしてmerge()を使うと移動するのでしょうか?
operator+=のときは単純に連結する仕様にしたので、たぶん移動することは無いと思います。
現在はこんな感じです↓

CODE:

#include 
#include 
#include 

template 

class slist :public std::list{
	iterator itBeg;
	iterator itEnd;

public:

	SLIST& operator[] (const int &num){
		iterator it = begin();
		std::advance(it, num);
		return *it;
	}

	slist& operator+= (const slist &slist){
		insert(end(), slist.begin(), slist.end() );
		return *this;
	}
	
	slist& operator+= (const std::list &list){
		insert(end(), list.begin(), list.end() );
		return *this;
	}

	slist& operator+= (const SLIST &ele){
		push_back(ele);
		return *this;
	}

	slist& operator+= (const std::vector &arr){
		insert(end(), arr.begin(), arr.end() );
		return *this;
	}

	slist& operator= (const std::list &list){
		clear();
		insert(end(), list.begin(), list.end() );
		return *this;
	}

	slist& operator= (const SLIST &ele){
		clear();
		push_back(ele);
		return *this;
	}

	slist& operator= (const std::vector &arr){
		clear();
		insert(end(), arr.begin(), arr.end() );
		return *this;
	}

	void reit(){
		itBeg = begin();
		itEnd = rend();
	}

	void setit(const int num){
		reit();
		std::advance(itBeg, num);
		itEnd = itBeg;
	}

	void operator= (const int &num){
		setit(num);
	}

	void operator! (void){
		reit();
	}

	SLIST& inc(){
		SLIST &iterEle = *itBeg;
		itBeg++;
		return iterEle;
	}

	SLIST& operator++ (void){
		return inc();
	}

	SLIST& operator++ (int){
		return inc();
	}

	SLIST& dec(){
		SLIST &iterEle = *itEnd;
		itEnd--;
		return iterEle;
	}

	SLIST& operator-- (void){
		return dec();
	}

	SLIST& operator-- (int){
		return dec();
	}
};
いや~、insert()便利ですね。

CODE:

list1.insert(list1.end(), nums, nums + 5);
insert()にこんな使用法があったとは知りませんでした。てっきり一つずつしか無理なのかと思っていました。
だから配列変数用の結合関数は廃止しました。