オブジェクトの定義とSTLについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ただの屍のようだ

オブジェクトの定義とSTLについて

#1

投稿記事 by ただの屍のようだ » 6年前

その1:new Project()ではポインタを返されるのでエラーになると思いますが、
Project(引数)という定義の仕方はいってしまえばコンストラクターを直接呼び出してる処理だと思いますがなぜエラーにならないのかという疑問です。
その2:せっかく比較演算子をオーバーロードしているにもかかわらず、void list<>::merge(list<>&)はなぜそれを使わないのかという質問です。

コード:

#include<iostream>
#include<cstring>
#include<list>
using namespace std;

class Project{
	char name[40];
	int days;
public:
	Project(){days=0;*name='\0';}
	Project(char *s,int d){strcpy(name,s);days=d;}
	Project &operator+(int n){this->days+=n; return *this;}
	Project &operator-(int n){this->days-=n; return *this;}
	int empty(){return !days;}
	friend ostream &operator<<(ostream &,Project &);
	operator int(){return this->days;}
	int operator==(Project &o){return (int)*this==(int)o;}
	int operator<(Project &o){return (int)*this < (int)o;}
	int operator>(Project &o){return (int)*this > (int)o;}
	int operator!=(Project &o){return (int)*this!=(int)o;}
};

ostream &operator<<(ostream &stream,Project &o){
	stream << o.name << "残り:" << o.days << "日\n";
	return stream;
}

int main(){
	list<Project> l1,l2;
	list<Project>::iterator p;
	l1.push_back(Project("コンパイラ",35));		//なぜnew Project(引数)ではエラーになるのか
	l1.push_back(Project("スプレッドシート",190));
	l1.push_back(Project("STL実装",1000));

	l2.push_back(Project("データベース",780));
	l2.push_back(Project("メールマージ",50));
	l2.push_back(Project("COMオブジェクト",300));

	l1.merge(l2);
	p = l1.begin();
	while(p!=l1.end())
		cout << *p++;
	p = l1.begin();
	cout << ((int)*p > (int)*++p);
	return 0;
}

nil
記事: 428
登録日時: 7年前

Re: オブジェクトの定義とSTLについて

#2

投稿記事 by nil » 6年前

その1
new Project(~~)はおっしゃるとおりポインタを返すため、
実体であるpush_back()の引数には渡せないからです。

これは
int i = new int( 10 );
がエラーになるのと同じ理由です。

std::list<Project*>とすればnew Project(~~)をpush_backの引数に渡せます。

Project(~~)は実体を返すためpush_back()の引数に渡せます。

その2
質問の意図をはかりかねたのでどのような動作を望んでいるのかの補足をお願いします。
こちらについては当方の知識の範囲外のため、
正確な回答をすることが出来ませんでした。

[追記]
C++を意識するのであればchar[]ではなくstd::stringを用いたほうが良いのでは、と思います。

[追記2]
Project(~~)を引数に渡せるのは
int i = int( 10 );
が可能であることと理屈は同じ(はず)です。
最後に編集したユーザー nil on 2013年5月22日(水) 13:31 [ 編集 2 回目 ]

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

Re: オブジェクトの定義とSTLについて

#3

投稿記事 by h2so5 » 6年前

list::mergeを使用する場合、マージ前に各listの要素がソートされている必要があります。
ソートされていない場合は意図しない結果になります。

http://www.cplusplus.com/reference/list/list/merge/
This function requires that the list containers have their elements already ordered by value (or by comp) before the call.

アバター
usao
記事: 1546
登録日時: 6年前

Re: オブジェクトの定義とSTLについて

#4

投稿記事 by usao » 6年前

new Project(); では返されるのがポインタ(Project *型)なので,
Project型を引数にとる std::list<Project>::push_back() の引数に与えようとしたらエラーになるのはそのとおり.

>Project(引数)という定義の仕方はいってしまえばコンストラクターを直接呼び出してる処理だと思いますがなぜエラーにならないのかという疑問
「コンストラクタを直接呼び出している」という言い方が正しいかどうかよくわかりませんが,
Project型には複数のコンストラクタがあり,
Project型インスタンスを作る際の書き方(引数,というか)によって,どのコンストラクタが使われるかが選ばれるので,

コード:

Project Instance( "hello", 5 );
と書けば,引数無しコンストラクタProject()ではなく,Project(char*,int)の方が呼ばれることになります.
で,

コード:

Project( "hello", 5 );
Project();
みたく,変数名がない形で書いた場合は,作られるインスタンスは,名前なしの一時オブジェクト になります.
こいつらの寿命は,「自身が作られた文の処理が終わるまで」(でいいのかな?言葉的に)という儚いものですが,
提示されたコードでpush_back()に渡されているオブジェクトのように,「関数に引数として渡すためだけに必要で,それ以降必要ない」オブジェクトは,これで事足ります.

>その2
merge()は2つのリストが共にソート済みでなければならないハズですが,そのへんで変な結果になっているとか?


…と,投稿しようとしたら他の方が回答されていますが,せっかくだからそのまま投稿します.

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

Re: オブジェクトの定義とSTLについて

#5

投稿記事 by YuO » 6年前

ただの屍のようだ さんが書きました:その1:new Project()ではポインタを返されるのでエラーになると思いますが、
Project(引数)という定義の仕方はいってしまえばコンストラクターを直接呼び出してる処理だと思いますがなぜエラーにならないのかという疑問です。
new演算子は動的記憶域期間をもつオブジェクトの生成のための演算子です。
また,new TはT *型の戻り値をもつ式です。
list<T>::push_backの引数は,const T &またはT &&です。なので,T *を渡すことはできません。

次に,式中のT(x, y, ... )のような表現は,基本的には一時オブジェクトの生成式です。
生成された一時オブジェクトはT型のprvalue (C++11)/rvalue (C++98)なので,const T &やT &&に渡すことが出来ます。
ただの屍のようだ さんが書きました:その2:せっかく比較演算子をオーバーロードしているにもかかわらず、void list<>::merge(list<>&)はなぜそれを使わないのかという質問です。
ちゃんとoperator<が使われているはずですが。

list::mergeはソート済みのlist同士をmergeするものです。
今回の場合は,l2が未ソートなので,未定義の振る舞いとなります。
# VS 2012ではデバッグ実行時に未ソートを検出してassertを吐きます。

なお,比較演算子は通常

コード:

bool operator @ (const T & rhs) const { return this->key @ rhs.key; }
という形をとります。
# operator!=は==から,operator>とoperator<=とoperator>=は<から生成することも出来ますが。
比較演算子に変更は不要なので,constを付けた方がよいでしょう。

また,operator+やoperator-が自身を書き換えるのも違和感があります。
自身を書き換えるoperator+=やoperator-=を定義し,

コード:

T operator @ (int n) const { return T(*this) @= n; }
のように書くのが常套句です。

ただの屍のようだ

Re: オブジェクトの定義とSTLについて

#6

投稿記事 by ただの屍のようだ » 6年前

なるほど。理解できました。
ありがとうございます。

閉鎖

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