拷贝函数之类型萃取

经常在写模板顺序表的时候遇到一个问题,在拷贝元素的时候应该用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;
    }

运行结果
这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值