C++って本当に重いの??

C++が重いとか、余分なRAMを使うと言われる理由を探してみます。

簡単なコードとアセンブリを用意。

MinGWでコンパイルしたので余分なアセンブリが入っていると思います。

class test
{
public:
	int data1;
	int data2;
	void aaa()
	{
		data1 = 1234;
	}
	;
};

volatile void sub3()
{
	test* ts = new test;
	ts->aaa();
	ts->data1 = 300;
}

volatile void sub2()
{
	test ts;
	ts.aaa();
	ts.data1 = 200;
}

volatile void sub1()
{
	test ts;
	ts.aaa();
	ts.data1 = 100;
}

int main()
{
	sub1();
	sub2();
	sub3();

	return 0;
}
	.file	"test02.cpp"
	.text
	.align 2
.globl __Z4sub3v
	.def	__Z4sub3v;	.scl	2;	.type	32;	.endef
__Z4sub3v:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	movl	$8, (%esp)
	call	__Znwj
	movl	%eax, -4(%ebp)
	movl	-4(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZN4test3aaaEv
	movl	-4(%ebp), %eax
	movl	$300, (%eax)
	leave
	ret
	.section	.text$_ZN4test3aaaEv,"x"
	.linkonce discard
	.align 2
.globl __ZN4test3aaaEv
	.def	__ZN4test3aaaEv;	.scl	2;	.type	32;	.endef
__ZN4test3aaaEv:
	pushl	%ebp
	movl	%esp, %ebp
	movl	8(%ebp), %eax
	movl	$1234, (%eax)
	popl	%ebp
	ret
	.text
	.align 2
.globl __Z4sub2v
	.def	__Z4sub2v;	.scl	2;	.type	32;	.endef
__Z4sub2v:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$24, %esp
	leal	-8(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZN4test3aaaEv
	movl	$200, -8(%ebp)
	leave
	ret
	.align 2
.globl __Z4sub1v
	.def	__Z4sub1v;	.scl	2;	.type	32;	.endef
__Z4sub1v:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$24, %esp
	leal	-8(%ebp), %eax
	movl	%eax, (%esp)
	call	__ZN4test3aaaEv
	movl	$100, -8(%ebp)
	leave
	ret
	.def	___main;	.scl	2;	.type	32;	.endef
	.align 2
.globl _main
	.def	_main;	.scl	2;	.type	32;	.endef
_main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	andl	$-16, %esp
	movl	$0, %eax
	addl	$15, %eax
	addl	$15, %eax
	shrl	$4, %eax
	sall	$4, %eax
	movl	%eax, -4(%ebp)
	movl	-4(%ebp), %eax
	call	__alloca
	call	___main
	call	__Z4sub1v
	call	__Z4sub2v
	call	__Z4sub3v
	movl	$0, %eax
	leave
	ret
	.def	__Znwj;	.scl	2;	.type	32;	.endef

見たところ、むしろ非常に効率よく処理してるような気がします。
少なくとも、ROMからRAMへコードはコピーされないことが確認できます。

テンプレートや例外はまた今度

Cで簡易Vector

CでVectorが使えないならそっれっぽいのを作ればいいというわけで、
昨晩チョコっとCで擬似的に作ったCVectorをメモメモ
戻り値とかコメントとかエラー処理が無かったり、 いろいろと中途半端だけど一応動きます。

Templateが使えないので、いちいちキャストが必要なことと、
複数vectorを管理したい時に、いちいちパラメータをセットしないといけないのが微妙です。。
たぶん良い解決方法があるんだと思うけど思いつかない!

main.c

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

int main()
{
	/*■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
		サンプルプログラム
	■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ */

	/* ダミーデータ */
	PHONE_LIST ts1;
	PHONE_LIST ts2;

	/* 実体 */
	C_VECTOR ldata;

	memcpy(ts1.data.name, "bbbbb", sizeof("bbbbb"));
	memcpy(ts2.data.name, "aaaaa", sizeof("aaaaa"));

	/* C_VECTORのparameteセットと、開始 */
	CVECTOR_PARAMETER_SET(&ldata);
	CVECTOR_START(&ldata, sizeof(PHONE_LIST));

	int size;
	PHONE_LIST *tmp;

	/* push_back */
	ldata.push_back(&ts1);
	size = ldata.size();
	printf("%d\n", size);

	ldata.push_back(&ts2);
	size = ldata.size();
	printf("%d\n", size);

	/* at */
	tmp = (PHONE_LIST*)ldata.at(0);
	printf("%s\n", tmp->data.name);

	/* swap */
	ldata.swap(0, 1);
	tmp = (PHONE_LIST*)ldata.at(0);
	printf("%s\n", tmp->data.name);

	/* erase */
	ldata.erase(0);
	tmp = (PHONE_LIST*)ldata.at(0);
	printf("%s\n", tmp->data.name);

	/* insert */
	ldata.insert(&ts1, 0);
	tmp = (PHONE_LIST*)ldata.at(0);
	printf("%s\n", tmp->data.name);

	/* clear */
	ldata.clear();
	size = ldata.size();
	printf("%d\n", size);


	/* C_VECTORの開放 */
	CVECTOR_END();

	return 0;
}

cvector.h

#ifndef __CVECTOR_H__
#define __CVECTOR_H__

/* 変数命令規則 */
#ifndef __VARIABLE_RULE__
#define __VARIABLE_RULE__
typedef unsigned int ui;
typedef unsigned char u1;
typedef unsigned short u2;
typedef unsigned long int u4;
typedef unsigned long long int u8;
typedef signed int si;
typedef signed char s1;
typedef signed short s2;
typedef signed long int s4;
typedef signed long long int s8;
#endif

#ifndef __CPRINT__
#define __CPRINT__
#include <stdio.h>
#define _PL(str) printf(str)
#endif

#ifndef __CFOR__
#define __CFOR__
#define FOR(i, j) for(i = 0; ((i) < (j)); ((i)++))
#endif

/* リスト管理構造体 */
typedef struct VECLIST
{
	struct VECLIST* next;				/* 前要素	*/
	struct VECLIST* prev;				/* 次要素	*/
	void* address;						/* アドレス */

}VECLIST;

typedef struct CVECTOR_PARAMETER
{
	VECLIST* pri_head;				/* 先頭要素				*/
	VECLIST* pri_tail;				/* 最終要素				*/
	si pri_Elementcnt;				/* 要素数				*/
	si pri_ElementSize;				/* 要素サイズ			*/
	si pri_EraseFlag;				/* _Erase関数が呼ばれると1	*/

	VECLIST* Search_tmp;
	VECLIST* Search_tmp_next;
	si LastSearchNo;
	si search_firstflag;

}CVECTOR_PARAMETER;


typedef struct _C_VECTOR
{
	/* 個々のリストを管理するためのparameter */
	CVECTOR_PARAMETER parameter;

	void* (*at)(int _Dst);
	int (*insert)(void *_Src, int _Dst);
	int (*push_back)(void *_Src);
	int (*size)();
	int (*swap)(int _target1, int _target2);
	int (*erase)(int _Dst);
	int (*clear)();

}C_VECTOR;

/* プロトタイプ宣言 */
int CVECTOR_START(C_VECTOR *_Ldata, int Size);
int CVECTOR_END();
void CVECTOR_PARAMETER_SET(C_VECTOR* _Src);


#endif
&#91;/c&#93;

cvector.c
&#91;c&#93;
#include "cvector.h"
#include <stdlib.h>
#include <string.h>


/* 静的プロトタイプ宣言 */
static VECLIST* Search(si _Dst);
static void* _At(si _Dst);
static si _Insert(void *_Src, si _Dst);
static si _Push_back(void *_Src);
static si _Size();
static si _Swap(si _target1, si _target2);
static si _Erase(si _Dst);


/* 静的グローバル変数 */
static CVECTOR_PARAMETER* g_parameter;

/*******************************************************************************
	概要		:	要素番号を検索します
	説明		:	内部関数なので、外部から呼び出されることはありません
	Include	:	
	引数		:	要素番号(int型)
	戻り値	:	VECLIST *
	Global	:	CVECTOR_PARAMETER g_parameter;
*******************************************************************************/
static VECLIST* Search(si _Dst)
{


	/* 最初の一回だけ処理 */
	if(g_parameter->search_firstflag)
	{
		g_parameter->search_firstflag = 0;
		g_parameter->Search_tmp = g_parameter->pri_head;
	}

	/* 前回に_Erase関数が呼ばれていた */
	if(g_parameter->pri_EraseFlag)
	{
		g_parameter->Search_tmp = g_parameter->Search_tmp_next;
		g_parameter->pri_EraseFlag = 0;
	}

	/* 前回検索した番号と今回検索する番号が同じだったなら */
	if(g_parameter->LastSearchNo == _Dst)
		return g_parameter->Search_tmp;
	
	if((_Dst - g_parameter->LastSearchNo) > 0)
	{
		/* 前方向探査 */
		si cnt;
		FOR(cnt, (_Dst - g_parameter->LastSearchNo))
		{
			/* 末端まで検索したら強制終了 */
			if(!g_parameter->Search_tmp->next)
				break;

			g_parameter->Search_tmp = g_parameter->Search_tmp->next;
		}
	}
	else
	{
		/* 後方向探査 */
		si cnt;
		FOR(cnt, (g_parameter->LastSearchNo - _Dst))
		{
			/* 末端まで検索したら強制終了 */
			if(!g_parameter->Search_tmp->prev)
				break;

			g_parameter->Search_tmp = g_parameter->Search_tmp->prev;
		}
	}

	/* 最後に検索したリストの番号を記憶 */
	g_parameter->LastSearchNo = _Dst;
	
	/* _Erase対策 */
	g_parameter->Search_tmp_next =g_parameter-> Search_tmp->next;
	return g_parameter->Search_tmp;
}

/*******************************************************************************
	概要		:	指定した要素を取り出します
	説明		:	void型のポインタが戻り値なので、明示的にキャストする必要があります。
	Include	:	
	引数		:	要素番号(int型)
	戻り値	:	void *
	Global	:	CVECTOR_PARAMETER g_parameter;
*******************************************************************************/
static void* _At(si _Dst)
{
	VECLIST* Search_tmp = Search(++_Dst);

	/* headかtailだった場合error */
	if(!Search_tmp->address)
		return NULL;

	return (void*)Search_tmp->address;
}

/*******************************************************************************
	概要		:	リストへ要素を格納します
	説明		:	登録したい要素を、指定した場所へ挿入します
	Include	:	
	引数		:	要素のポインタ, 挿入したい場所(int型)
	戻り値	:	成功なら0不成功なら1を返します
	Global	:	CVECTOR_PARAMETER g_parameter;
*******************************************************************************/
static si _Insert(void *_Src, si _Dst)
{
	void* data_tmp;
	VECLIST* list_tmp;
	VECLIST* Search_tmp = g_parameter->pri_head;

	data_tmp = malloc(g_parameter->pri_ElementSize);
	memmove(data_tmp, _Src, g_parameter->pri_ElementSize);

	list_tmp = (VECLIST*)calloc(1, sizeof(VECLIST));
	list_tmp->address = data_tmp;

	Search_tmp = Search(_Dst);

	/* リストへ挿入 */
	/*■  Search_tmp <-> list_tmp <-> Search_tmp->next  ■*/
	list_tmp->next = Search_tmp->next;
	list_tmp->prev = Search_tmp;
	Search_tmp->next->prev = list_tmp;
	Search_tmp->next = list_tmp;
	
	/* 要素数カウントアップ */
	g_parameter->pri_Elementcnt++;
	return 0;
}

/*******************************************************************************
	概要		:	リストへ要素を格納します
	説明		:	登録したい要素を一番最後のリストへ挿入
	Include	:	
	引数		:	要素のポインタ
	戻り値	:	成功なら0不成功なら1を返します
	Global	:	CVECTOR_PARAMETER g_parameter;
*******************************************************************************/
static si _Push_back(void *_Src)
{
	/* 一番最後のリストへ挿入 */
	_Insert(_Src, g_parameter->pri_Elementcnt);
	return 0;
}

/*******************************************************************************
	概要		:	現在の要素の数を返します
	説明		:	現在の要素の数をint型で返します。
	Include	:	
	引数		:	無し
	戻り値	:	要素数(int型)
	Global	:	CVECTOR_PARAMETER g_parameter;
*******************************************************************************/
static si _Size()
{
	return g_parameter->pri_Elementcnt;
}

/*******************************************************************************
	概要		:	指定された要素の場所を入れ替えます
	説明		:	現在のparameterのセットされているリストを入れ替えますします
	Include	:	
	引数		:	要素番号1(int型の数値), 要素番号2(int型の数値)
	戻り値	:	成功なら0不成功なら1を返します
	Global	:	CVECTOR_PARAMETER g_parameter;
*******************************************************************************/
static si _Swap(si _target1, si _target2)
{
	VECLIST* Search_tmp1, * Search_tmp2;
	void* tmp;
	Search_tmp1 = Search(++_target1);
	Search_tmp2 = Search(++_target2);

	/* headかtailだった場合error */
	if(!Search_tmp1->address || !Search_tmp2->address)
		return 1;

	/* 要素の入れ替え ※リストは変更しない */
	tmp = Search_tmp1->address;
	Search_tmp1->address = Search_tmp2->address;
	Search_tmp2->address = tmp;

	return 0;
}

/*******************************************************************************
	概要		:	指定された要素をクリアします
	説明		:	現在のparameterのセットされているリストをクリアします
	Include	:	
	引数		:	要素番号(int型の数値)
	戻り値	:	成功なら0不成功なら1を返します
	Global	:	CVECTOR_PARAMETER g_parameter;
*******************************************************************************/
static si _Erase(si _Dst)
{

	VECLIST* Search_tmp;
	Search_tmp = Search(++_Dst);

	/* リストのつなぎ替え */
	Search_tmp->prev->next = Search_tmp->next;
	Search_tmp->next->prev = Search_tmp->prev;

	/* リストと要素を開放 */
	free(Search_tmp->address);
	free(Search_tmp);

	/* _Erase実行済みフラグON */
	g_parameter->pri_EraseFlag = 1;

	g_parameter->pri_Elementcnt--;
	return 0;
}

/*******************************************************************************
	概要		:	リスト構造の要素をすべてクリアします
	説明		:	現在のparameterのセットされているリストをクリアします
	Include	:	
	戻り値	:	成功なら0不成功なら1を返します
	Global	:	CVECTOR_PARAMETER g_parameter;
*******************************************************************************/
static si _Clear()
{
	si cnt;
	si Frequency = g_parameter->pri_Elementcnt;
	FOR(cnt, Frequency)
	{
		_Erase(0);
	}
	return 0;
}


/* 外部関数 ----------------------------------------------*/


/*******************************************************************************
	使い方	:	必ず最初に呼び出します。
	概要		:	CVECTORが利用するparameterをセットします
	説明		:	複数のリストを管理するために、parameterを分離させます
	Include	:	cvector.h stdlib.h
	引数		:	C_VECTOR *_Ldata	;オブジェクト
				int Size			;リストの要素サイズを指定します
	戻り値	:	成功なら0不成功なら1を返します
	Global	:	CVECTOR_PARAMETER g_parameter;
*******************************************************************************/
void CVECTOR_PARAMETER_SET(C_VECTOR* _Src)
{
	g_parameter = &_Src->parameter;
}

/*******************************************************************************
	使い方	:	必ず最初に呼び出します。
	概要		:	CVECTORの全体の処理を開始します
	説明		:	構造体の初期化と、メソッドをセットします
	Include	:	cvector.h stdlib.h
	引数		:	C_VECTOR *_Ldata	;オブジェクト
				int Size			;リストの要素サイズを指定します
	戻り値	:	成功なら0不成功なら1を返します
	Global	:	CVECTOR_PARAMETER g_parameter;
*******************************************************************************/
si CVECTOR_START(C_VECTOR *_Ldata, int Size)
{
	
	/* リストの先頭と後尾の空要素作成 */
	VECLIST* head = (VECLIST*)calloc(1, sizeof(VECLIST));
	VECLIST* tail = (VECLIST*)calloc(1, sizeof(VECLIST));

	/* parameterの初期化 */
	memset(&_Ldata->parameter, 0, sizeof(_Ldata->parameter));

	g_parameter->pri_head = head;
	g_parameter->pri_tail = tail;

	/* リスト構造の構築 */
	g_parameter->pri_head->next = tail;
	g_parameter->pri_head->prev = NULL;
	g_parameter->pri_tail->prev = head;
	g_parameter->pri_tail->next = NULL;


	/* メソッドを構造体へ格納 */
	_Ldata->at			= _At;
	_Ldata->insert		= _Insert;
	_Ldata->erase		= _Erase;
	_Ldata->push_back	= _Push_back;
	_Ldata->size		= _Size;
	_Ldata->swap		= _Swap;
	_Ldata->clear		= _Clear;

	/* 要素サイズ格納 */
	g_parameter->pri_ElementSize = Size;

	/* _Serch関数フラグ */
	g_parameter->search_firstflag = 1;
	
	return 0;
}

/*******************************************************************************
	使い方	:	プラグラムの一番最後に必ず呼び出します
	概要		:	C_VECTORを終了します
	説明		:	全ての要素をFreeしたあと、ダミーデータをFreeします
	Include	:	cvector.h stdlib.h
	戻り値	:	成功なら0不成功なら1を返します
	Global	:	CVECTOR_PARAMETER g_parameter;
*******************************************************************************/
si CVECTOR_END()
{
	_Clear();
	free(g_parameter->pri_head);
	free(g_parameter->pri_tail);

	return 0;
}

C言語のマクロで便利そうなもの

C言語のマクロで面白そうなものをメモ!

#include

#define _PFP(str) printf("%s\n", str)
#define ASIZEOF(array) (sizeof(array) / sizeof(array[0]))
#define FOR(i, j) for(((i) = 0); ((i) &lt; (j)); ((i)++))
#define ISR(str) str, #str

enum etest{ aaa, bbb, ccc };

typedef struct _stest
{
    enum etest yyy;
    char *name;
}stest;

int main()
{
    int i;

    stest ts[] = { ISR(aaa), ISR(bbb), ISR(ccc) };

    FOR(i, ASIZEOF(ts))
        _PFP(ts[i].name);

}

enumとマクロの組み合わせ
for文
配列の要素数を求める

の3つが特に面白いとおもう。
積極的にマクロを使うのもいいかなーっ

ただ、マクロが嫌いな人もいると思うので、使っていいのか悩みどころ。。

C++の使用禁止Cネイティブ機能だけ

クラスの概念がないと不便なので Cで似たようなことをすればいいと思って。。

思いついた擬似クラスの様なものをメモメモ


#include <stdio.h>

/* 擬似クラス */
struct Stest
{
	void (*out)();
};

/* 擬似メンバ関数 */
void out()
{
	printf("TEST\n");
}
/* 擬似コンストラクタ */
void stest(Stest* _Src)
{
	_Src->out = out;
}

void main()
{
	Stest st;
	stest(&st);    /* 手動コンストラクタ */

	st.out();
}