1

我有以下代码

size_t returnSize(const char* s)
{
       string string(s);
       return string.size();
};

size_t returnSize(const int& i)
{
       return sizeof(i);
};


template<typename T>
vector<char> Serialize(const T& t)
{
    T* pt = new T(t);
    vector<char> CasttoChar;

    for (int i =0 ;i<returnSize(t);i++)
    {
        CasttoChar.push_back(reinterpret_cast<const char*>(pt)[i]);
    }
    delete pt;
    return CasttoChar;
};
template<typename T>
T DeSerialize(const vector<char> cstr)
{
    T* a = (T*)(&cstr[0]);

    return *a;
}

int _tmain(int argc, _TCHAR* argv[])
{
    int x = 97;
    vector<char> c = Serialize(x);
    cout << DeSerialize<int>(c) << endl;

    string k = "blabla";
    vector<char> c3 = Serialize(k.c_str());
    cout << DeSerialize<const char*>(c3) << endl;

    system("PAUSE");
    return EXIT_SUCCESS;
}

//output is 
//97
//blabla

这条线路T* a = (T*)(&cstr[0]);安全吗?

另外,我尝试reinterpret_cast<T*>(&cstr[0]);了,T* a = (T*)(&cstr[0]);但编译器抱怨无法将 const char* 转换为 int*。那么为什么 C 风格的演员表会起作用呢?

4

5 回答 5

3

参考标准

为什么 reinterpret_cast 失败?

5.2.10 重新解释演员表 [expr.reinterpret.cast]

reinterpret_cast 运算符不应抛弃 constness (5.2.11)。整数、枚举、指针或指向成员类型的表达式可以显式转换为它自己的类型;这样的强制转换会产生其操作数的值。

我应该使用 C Cast 吗? 不,使用 C Cast 而不是 C++ Cast 总是不安全的。您正在尝试删除作为 UB 的对象的常量。使用 reinterpret_cast,实际上会捕获此错误,并在编译期间告知您潜在的陷阱。

你应该const_cast在这种情况下实际使用。const将对象转换为非const对象的唯一合法方法

但是为什么 C Cast 有效

引用问题何时应使用 static_cast、dynamic_cast 和 reinterpret_cast?

C 样式转换被定义为以下成功的第一个:

const_cast
static_cast
static_cast, then const_cast
reinterpret_cast
reinterpret_cast, then const_cast

幸运的是,它尝试了const_cast第一个。

于 2013-01-13T09:27:15.307 回答
2

C 风格的演员表之所以有效,是因为它需要许多步骤才能使演员表成功。它使用以下成功的第一个:

const_cast
static_cast
static_cast + const_cast
reinterpret_cast
reinterpret_cast + const_cast

在这种情况下,它正在执行最“强大”的演员阵容, a reinterpret_casttoconst int *后跟const_castto int*

单独不会编译,reinterpret_cast因为你正在抛弃 const-ness。const_cast需要强制转换为int*。但是,做一个reinterpret_casttoconst int*会很好。

顺便说一句,您所做的通常是不安全的,除非您使用编译器扩展来确保您要反序列化的任何用户定义类型都不会被填充。

于 2013-01-13T09:25:50.913 回答
0

C ++ 中的 C 样式强制转换并不是一个好主意,因为您通过了阻止您删除 const 或任意更改类型的检查。如果你想让代码按原样工作,你首先需要 const_cast 然后 reinterpret_cast,但尽量避免 const 强制转换。为了避免使用 reinterpret_cast 的警告,只需将 a 声明为const T*.

于 2013-01-13T09:25:32.397 回答
0

坚持使用 C++ 强制转换。不起作用的原因reinterpret_cast是你抛弃了 constness,这并不酷;您必须为此使用 a const_cast,而您不应该这样做。C 强制转换忽略了这一点。

话虽如此,你想在这里实现什么?您可以有效地转换为char数组并memcpying,而不会带来效率。

于 2013-01-13T09:26:29.633 回答
0

很抱歉在这里插话,但你的代码在几个方面被破坏了,演员表只是其中之一。关于强制转换,一旦您在不仅仅是一个简单的 int 左右但需要构造函数的东西上使用从/到向量的转换,它就会失败。无论如何,不​​幸的是,从char const*void const*到的两步转换T const*是必要的。

现在,其他问题:

  • 用一个零大小的字符串尝试整个事情。这现在也应该完全回答您的实际问题:不,这不安全。
  • 您正在返回一个指向 char 的指针DeSerialize<char const*>()。该指针指向给定向量所拥有的内存,该向量按值传递,从该函数返回后不复存在!它似乎起作用是纯粹的运气。
  • 即使您设法以某种方式char const*从函数中返回 a,请考虑现在谁拥有该内存。关键是这个所有者也必须释放内存。考虑使用模板的特殊化std::string并使变体不编译。char const*
  • 一般来说,如果你是认真的说这段代码,请开始添加单元测试。它现在可能会减慢您的速度,但可以避免在您离开时出现错误,从而总体上节省时间。搜索“测试驱动开发”。
  • 没有任何东西可以保证字符串是 NUL 终止的。
  • 除非必须,否则不要使用 new/delete,更喜欢“普通”堆栈变量。如果这样做,请注意在发生异常时正确释放内存(来自 push_back())。使用 auto_ptr (C++98) 或 unique_ptr (C++11) 确保内存被正确释放。
于 2013-01-13T10:23:34.633 回答