在铸造char *之前获得变量值的更好方法

时间:2014-08-20 07:09:53

标签: c++ c

在我们的遗留代码中,我们尝试将原始值从char *转换为某种特定类型,如int,float,double,char(一堆char)等。

代码如下所示

char *data = db_data(process, retry_column);
int retry_time = *(int*)(data);
//......
data = db_data(process, user_name_column);
std::string user_name(data, std::strlen(data));

在不重新设计库的情况下获得变体数据类型的更好方法是什么?

如果唯一的方法是重新设计库,你会建议什么样的解决方案,而不是在性能和​​类型安全之间进行压缩(我希望同时获得两者),boost :: variant可以完成任务吗?

3 个答案:

答案 0 :(得分:1)

如果您想要类型安全,您应该毫无疑问选择boost::variant

但是,这需要你重新编译db_data(),因为返回不再是char *。

因此,如果有太多事情需要完成,并且您希望从更轻松的变化开始,我可以为您提出以下模板和字符串案例的专业化:

template <typename T> 
inline T vdata(char* val) 
   { return *reinterpret_cast<T*>(val); }     

template<>
inline string vdata(char* val) 
   { return string(val); }  // special case for strings 

注意:此模板按值运行。因此它与你的解除引用的铸造指针略有不同,因为你不能将它用作左值来为它赋值(而*(int*)data = 12;将是有效的)

使用此定义,您可以更改这样的遗留代码:

int retry_time = vdata<int>(data);
... 
std::string user_name = vdata<string>(data);

当然,您可以通过避免使用临时数据来使其更简单:

模板 inline T vdb_data(int proc,char * col)//注意:使用与原始相同的参数签名,我不知道你使用的真实类型    {return vdata(db_data(proc,col)); }

但有些人指出,这个解决方案很不错,但不会给你带来类型安全。例如,在字符串版本中,至少进行一些一致性检查会很好(例如它终止,并且长度符合str :: max_size()。)

答案 1 :(得分:0)

显而易见的解决方案是boost::variant

即便如此,提供retry_column类型int_column_t以便使用int db_data(..., int_column_t)重载可能很有用。

答案 2 :(得分:0)

有一个固有的问题,就是无法知道你得到的字节是否确实是正确的类型。它们只是0和1的流。因此无法确保数据库中的数据是正确的类型(除了数据大小考虑因素)。话虽这么说,你可以通过在数据类型上模板化db_data来避免客户端代码中的强制转换。然后,它可以验证大小是否正确,然后返回已转换为正确类型的数据。这将是这样的:

template<class DataType> DataType db_data();