std::listでnew・deleteをオーバーロード

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
夢幻ノ月夜
記事: 140
登録日時: 5年前
住所: Stens;Gate世界線

std::listでnew・deleteをオーバーロード

#1

投稿記事 by 夢幻ノ月夜 » 4年前

基底クラスとなるTaskクラスを定義し、そこから敵やら弾やらのクラスを派生する形で作っているのですが、
std::listに項目を追加・削除する作業をnew・deleteのオーバーロードで行いたいです。
(Taskの派生クラスの中ではnewとdeleteをタスクリストに追加削除すると定義したい)
deleteの中では普通に削除するだけですが、newには描画優先度も引数として持たせたいです
ソートは<をオーバーロードして実装するつもりですが、
newとdeleteでlistに追加・削除するにはどうしたらいいでしょうか
どうやらnewはsize_tを受け取ってvoid*を返しているようなのですが…
具体的に何をやっているのかよく分かりません
なお目的は「delete this;」で自分自身を削除出来ることです

↓現時点でのコード

コード:

#include <list>

using namespace std;

class Task{
protected:
	int m_id;
	float priority;
public:
	void* operator new(size_t size,float priority=0.5f);
	void operator delete(void* pTask);
};

list<Task*> TaskList;
毎回ゲーム作ろうとするたびに壁にぶち当たる

アバター
tk-xleader
記事: 153
登録日時: 9年前
連絡を取る:

Re: std::listでnew・deleteをオーバーロード

#2

投稿記事 by tk-xleader » 4年前

 operator newは、第一引数にnew演算子の型のバイトサイズが渡されます。そして、少なくとも第一引数のバイト数は書き込み可能なメモリブロックを戻り値とします。他方、operator deleteは、delete演算子のオペランドのメモリブロックがそのまま渡されます。そのメモリブロックは既に解体済み(デストラクタが呼ばれた後)なので、通常はメモリブロックの解放処理を記述します。

 原則として、operator new/deleteがやるべきことはメモリブロックの確保/解放(placement newの場合は受け取ったメモリブロックをそのまま返すだけですが)なので、そこでTask型の存在を前提とした処理を行うということは普通はしないのではないかと思います。通常ならそれはコンストラクタ/デストラクタの仕事ではないかと。

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

Re: std::listでnew・deleteをオーバーロード

#3

投稿記事 by YuO » 4年前

あくまでoperator new,operator deleteのオーバーロードであって,new operatorやdelete operatorのオーバーロードではありません。
また,new operator/delete operatorはオーバーロードできません。
つまり,malloc/free相当部分は変更が出来るものの,コンストラクタの呼び出しやその引数は変更できません。
このため,operator newの引数をオブジェクトに引き渡すには,別の領域に保持しておいて,そこから値を取得するしかありません。

なお,operator newには対応するoperator deleteが原則的に必要です。
void * operator new (std::size_t, float)に対応するのは,void operator delete (void *, float)またはvoid operator delete (void *, std::size_t, float)です。
コンストラクタで例外を発生させた場合などに,こちらのoperator deleteが呼ばれます。
# deleteした場合は通常のoperator deleteが呼ばれるので注意。

sleep

Re: std::listでnew・deleteをオーバーロード

#4

投稿記事 by sleep » 4年前

new、deleteについて
夢幻ノ月夜 さんが書きました: どうやらnewはsize_tを受け取ってvoid*を返しているようなのですが…
具体的に何をやっているのかよく分かりません
この辺のnew、deleteに関する知識は、STLで使用されているallocatorを自作してみると理解できます。
重要なのは4つの関数で行われている動作です。
allocate、deallocate、construct、destroy
これらが「いつ呼び出されて」「何をしているのか」が理解できれば、new、deleteの動作に関する疑問は解消されることでしょう。

Windows: VS 2015
Linux: gcc 5.2.1

コード:

//g++ -std=c++14 -o test test.cpp
#include <iostream>
#include <string>
#include <memory>
#include <new>
#include <cstddef>
#include <stdexcept>

template <class T>
class custom_allocator
{
public:
	static_assert(!std::is_const<T>::value, "custom_allocator<const T> is ill-formed.");

	using value_type = T;
	using pointer = value_type*;
	using const_pointer = const pointer;
	using reference = value_type&;
	using const_reference = const value_type&;
	using size_type = std::size_t;
	using difference_type = std::ptrdiff_t;

	template <class Other>
	struct rebind { using other = custom_allocator<Other>; };
	pointer address(reference value) const { return &value; }
	const_pointer address(const_reference value) const { return &value; }
	constexpr size_type max_size() const noexcept { return static_cast<size_type>(-1) / sizeof(T); }

	template <class Other>
	custom_allocator<value_type>& operator = (const custom_allocator<Other>&) const { return *this; }
	inline bool operator == (const custom_allocator&) const { return true; }
	inline bool operator != (const custom_allocator&) const { return false; }

	custom_allocator() noexcept {}
	custom_allocator(const custom_allocator&) noexcept {}
	template <class Other>
	custom_allocator(const custom_allocator<Other>&) noexcept {}

	pointer allocate(size_type count, const void* = 0) const throw(std::bad_alloc, std::length_error)
	{
		if (count == 0) return nullptr;
		if (count > max_size()) throw std::length_error("custom_allocator<value_type>::allocate(size_type count, const void* = 0)  ->   count > max_size()");

		void* const p = ::operator new (sizeof(value_type) * count, std::nothrow);
		if (p == nullptr) throw std::bad_alloc();

		std::cout << "allocate   : " << std::hex << p << std::dec << " <- " << sizeof(value_type) * count << " byte  [" << typeid(value_type).name() << " : " << sizeof(value_type) << " byte] * " << count << std::endl;

		return static_cast<pointer>(p);
	}
	void deallocate(pointer p, size_type count) const
	{
		if (p == nullptr) return;
		::operator delete((void*)p);

		std::cout << "deallocate : " << std::hex << p << std::dec << " -> " << sizeof(value_type) * count << " byte  [" << typeid(value_type).name() << " : " << sizeof(value_type) << " byte] * " << count << std::endl;
	}

	template <class ObjType, class... Args>
	void construct(ObjType *p, Args&&... args) const
	{
		std::cout << "construct  : " << typeid(ObjType).name() << std::endl;

		::new((void*)p) ObjType(std::forward<Args>(args)...);
	}
	template <class ObjType>
	void destroy(ObjType *p) const
	{
		std::cout << "destroy    : " << typeid(ObjType).name() << std::endl;

		p->~ObjType();
	}
};

#include <iostream>
#include <string>
#include <vector>
#include <deque>
#include <stack>
#include <list>
#include <unordered_map>
#include <iterator>
using namespace std;

class A
{
public:
	int a = 0;
	~A()
	{
		cout << "デストラクタ" << endl;
	}
};

int main()
{
#ifdef _WIN32
	_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
#endif

	{
		cout << "std::vector" << endl;
		cout << "-----------------------------------" << endl;
		auto v = std::vector<A, custom_allocator<A>>();
		//v.reserve(10);
		cout << "-----------------------------------" << endl;
		v.emplace_back();
		cout << "-----------------------------------" << endl;
		v.emplace_back();
		cout << "-----------------------------------" << endl;
		v.emplace_back();
		cout << "-----------------------------------";
		cin.ignore();
	}
	cout << "-----------------------------------" << endl;
	cin.ignore();
	{
		cout << "std::deque" << endl;
		cout << "-----------------------------------" << endl;
		auto v = std::deque<A, custom_allocator<A>>();
		cout << "-----------------------------------" << endl;
		v.emplace_back();
		cout << "-----------------------------------" << endl;
		v.emplace_back();
		cout << "-----------------------------------" << endl;
		v.emplace_back();
		cout << "-----------------------------------";
		cin.ignore();
	}
	cout << "-----------------------------------" << endl;
	cin.ignore();
	{
		cout << "std::stack (vector)" << endl;
		cout << "-----------------------------------" << endl;
		auto v = std::stack<A, vector<A, custom_allocator<A>>>();
		cout << "-----------------------------------" << endl;
		v.emplace();
		cout << "-----------------------------------" << endl;
		v.emplace();
		cout << "-----------------------------------" << endl;
		v.emplace();
		cout << "-----------------------------------";
		cin.ignore();
	}
	cout << "-----------------------------------" << endl;
	cin.ignore();
	{
		cout << "std::stack (deque)" << endl;
		cout << "-----------------------------------" << endl;
		auto v = std::stack<A, deque<A, custom_allocator<A>>>();
		cout << "-----------------------------------" << endl;
		v.emplace();
		cout << "-----------------------------------" << endl;
		v.emplace();
		cout << "-----------------------------------" << endl;
		v.emplace();
		cout << "-----------------------------------";
		cin.ignore();
	}
	cout << "-----------------------------------" << endl;
	cin.ignore();
	{
		cout << "std::list" << endl;
		cout << "-----------------------------------" << endl;
		auto v = std::list<A, custom_allocator<A>>();
		cout << "-----------------------------------" << endl;
		v.emplace_back();
		cout << "-----------------------------------" << endl;
		v.emplace_back();
		cout << "-----------------------------------" << endl;
		v.emplace_back();
		cout << "-----------------------------------";
		cin.ignore();
	}
	cout << "-----------------------------------" << endl;
	cin.ignore();
	{
		cout << "std::unordered_map" << endl;
		cout << "-----------------------------------" << endl;
		auto v = std::unordered_map<string, string, std::hash<string>, std::equal_to<string>, custom_allocator<std::pair<const string, string>>>();
		cout << "-----------------------------------" << endl;
		v["A"] = "hello";
		cout << "-----------------------------------" << endl;
		v["B"] = "byte";
		cout << "-----------------------------------" << endl;
		v["C"] = "good";
		cout << "-----------------------------------" << endl;
		cout << R"(v["A"] = )" << v["A"] << endl;
		cout << R"(v["B"] = )" << v["B"] << endl;
		cout << R"(v["C"] = )" << v["C"] << endl;
		cout << "-----------------------------------";
		cin.ignore();
	}
	cout << "-----------------------------------" << endl;
	cin.ignore();
}

アバター
夢幻ノ月夜
記事: 140
登録日時: 5年前
住所: Stens;Gate世界線

Re: std::listでnew・deleteをオーバーロード

#5

投稿記事 by 夢幻ノ月夜 » 4年前

次のゲーム作るときにリスト管理のプログラムを先に作ります(´・ω・`)
今のゲームは今の管理機構で完成させたいと思います(´・ω・`)
ありがとうございました(´・ω・`)
毎回ゲーム作ろうとするたびに壁にぶち当たる

アバター
いわん
記事: 29
登録日時: 4年前

Re: std::listでnew・deleteをオーバーロード

#6

投稿記事 by いわん » 4年前

newとdeleteの仕組みについて、興味があったので自分なりにコードを書いてみました。
一応動いているみたいですが、まだよくわかっていないこともあり問題あるコードだと思いますので詳しい方のチェックお願いします。
エラーチェック、例外発生時の対応等一切していません^^;

コード:

// compiler : Microsoft Visual C++ 2015
// project template : Win32 コンソールアプリケーション

#include "stdafx.h"

#include <list>
using namespace std;

class Task
{
protected:
	static list<Task*> TaskList;
	int m_id;
	float priority;
public:
	static void* operator new(size_t size, int id, float priority = 0.5f)
	{
		printf("new id=%d\n", id);
		Task *pTask = (Task*)malloc(size);
		pTask->m_id = id;
		pTask->priority = priority;
		TaskList.push_back(pTask);
		return pTask;
	}
	static void operator delete(void* pTask)
	{
		list<Task*>::iterator ite;
		for (ite = TaskList.begin(); ite != TaskList.end(); ++ite)
		{
			if (*ite == pTask)
			{
				printf("delete id=%d\n", (*ite)->m_id);
				TaskList.erase(ite);
				free(pTask);
				break;
			}
		}
	}
	static void PrintList()
	{
		printf("TaskList size = %d\n", TaskList.size());
		list<Task*>::iterator ite;
		for (ite = TaskList.begin(); ite != TaskList.end(); ++ite)
		{
			printf("m_id=%d priority=%g\n", ((Task*)*ite)->m_id, ((Task*)*ite)->priority);
		}
	}
};
list<Task*> Task::TaskList;

int main()
{
	Task *ptask1, *ptask2, *ptask3;
	ptask1 = new(1) Task;
	ptask2 = new(2, 1.0) Task;
	ptask3 = new(3, 1.5) Task;
	Task::PrintList();
	delete ptask2;
	Task::PrintList();
	delete ptask1;
	delete ptask3;
	Task::PrintList();
	return 0;
}

閉鎖

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