拷贝函数之类型萃取

来源:互联网 发布:苹果抹除数据后会怎样 编辑:程序博客网 时间:2024/06/08 12:58

经常在写模板顺序表的时候遇到一个问题,在拷贝元素的时候应该用for循环进行赋值,还是应用效率较高的memcpy.今天我们就来讨论一下。
首先看下它们各自的优缺点
(1) for 循环拷贝比较安全,容易想到并且实现;但是在顺序表元素太多时,时间复杂度高的情况下,for循环拷贝的效率比较低。
(2)memcpy是内存拷贝函数,任意内置类型的数据都可以拷贝,并且效率很高;但是memcpy的拷贝属于浅拷贝,在涉及字符串等自定义类型的数据时,拷贝会出现异常,程序会崩溃。
插入两个小概念:
1. POD:plain old data平凡类型(无关痛痒的类型)–基本类型
指在C++中与 C兼容的类型,可以按照 C的方式处理。
2. typeid可以获取到一个类型的名称,但是不能拿来做变量的声明。
下面介绍三种确定用for循环拷贝或者memcpy的方式。
第一种:封装一个判别是否是内置类型的函数IsPODtype();
bool IsPODtype(const char* type)
{
static char*arr[] = { "int", "char", "float", "double" };
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)
{
if (strcmp(arr[i], type) == 0)
return true;
else
return false;
}
return false;
}
static char*arr[] = { "int", "char", "float", "double" }是将属于内置类型的四个数据类型进行罗列,将要拷贝的类型进行比对。
这种方式的调用函数为
template <class T>
void Copy(T*dest, T*src, int sz)
{
if (IsPODtype(typeid(T).name()))
{
memcpy(dest, src,sz*sizeof(T));//若为内置类型,可用memcpy拷贝,提高效率。
}
else
{
for (int i = 0; i < sz; i++)//若为自定义类型,不能用memcpy拷贝,深浅拷贝问题,用赋值
{
dest[i] = src[i];
}
}
}
这种方式容易理解并且想到。

第二种:将类型名称当作特殊的数据类型,将内置类型进行特化,这样,在创建实例时,模板类函数会对类型进行推演,从而找到对应的模板函数。
下面来看代码

struct truename
{
static bool IsPODtype()
{
return true;
}
};

struct falsename
{
static bool IsPODtype()
{
return false;
}
};
template
struct name
{
typedef falsename PODtype;
};

template < >
struct name
{
typedef truename PODtype;
};

template < >
struct name
{
typedef truename PODtype;
};

template < >
struct name
{
typedef truename PODtype;
};

template < >
struct name
{
typedef truename PODtype;
};

函数调用
template
void Copy(T*dest, T*src, int sz)
{
if (name::PODtype::IsPODtype())
{
memcpy(dest, src, sz*sizeof(T));//若为内置类型,可用memcpy拷贝,提高效率。
}
else
{
for (int i = 0; i < sz; i++)//若为自定义类型,不能用memcpy拷贝,深浅拷贝问题,用赋值
{
dest[i] = src[i];
}
}
}

这种方式对模板函数进行特化,也是不错的方式。
第三种:这种方式也是建立在模板函数的特化上,将使用for这里写代码片循环还是memcpy拷贝进行函数封装,在主拷贝函数中调用次拷贝函数,三个函数构成函数重载

`
struct truename
{
};
struct falsename
{
};
template
struct name
{
typedef falsename PODtype;
};

template < >
struct name
{
typedef truename PODtype;
};

template < >
struct name
{
typedef truename PODtype;
};

template < >
struct name
{
typedef truename PODtype;
};

template < >
struct name
{
typedef truename PODtype;
};

template
void Copy(T* dest, T*src, int sz, truename)
{
memcpy(dest, src, sz*sizeof(T));
}
template
void Copy(T* dest, T*src, int sz, falsename)
{
for (int i = 0; i < sz; i++)
{
dest[i] = src[i];
}
}
template
void Copy(T*dest, T*src, int sz)
{
Copy(dest, src, sz, name::PODtype());
}
这种方式的实现也比较简单,关键是要理清思路。
`
看一下测试代码吧

int arr[4] = { 1, 2, 3, 4 };    int arr2[6] = { 0 };    int sz = sizeof(arr) / sizeof(arr[0]);    Copy<int>(arr2, arr, sz);    for (int i = 0; i < 6; i++)    {        cout << arr2[i] << endl;    }

注:第二种和第三种方式都是类型萃取的方式,大家要细细品味和理解。
运行结果:
这里写图片描述

char* arr1[4] = { "11", "22", "33", "44" };    char* arr3[4] = { "00" };    int sz1 = sizeof(arr1) / sizeof(arr1[0]);    Copy<char*>(arr3, arr1, sz1);    for (int i = 0; i < 4; i++)    {        cout << arr3[i] << endl;    }

运行结果
这里写图片描述

原创粉丝点击