std :: vector内存操作中的安全性

时间:2013-01-13 09:16:23

标签: c++ casting

我有以下代码

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风格的演员呢?

5 个答案:

答案 0 :(得分:3)

参考标准

为什么reinterpret_cast失败?

  

5.2.10重新解释cast [expr.reinterpret.cast]

     

reinterpret_cast运算符不应丢弃constness(5.2.11)。   整数,枚举,指针或指向成员的指针的表达式   type可以显式转换为自己的类型;这样的演员收益率   其操作数的值。

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

在这种情况下,您应该实际使用const_cast。它是将const对象转换为非const对象

的唯一合法方式

但是为什么C Cast会起作用

引用问题When should static_cast, dynamic_cast and reinterpret_cast be used?

中接受的答案
  

C样式演员被定义为以下第一个   成功:

const_cast
static_cast
static_cast, then const_cast
reinterpret_cast
reinterpret_cast, then const_cast

幸运的是,它先尝试const_cast

答案 1 :(得分:2)

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

const_cast
static_cast
static_cast + const_cast
reinterpret_cast
reinterpret_cast + const_cast

在这种情况下,它正在进行最“强大”的演员,reinterpret_castconst int *,然后是const_castint*

单独reinterpret_cast无法编译,因为你正在抛弃常量。 const_cast需要投放到int*。然而,对reinterpret_cast进行const int*会很好。

顺便说一句,你正在做的事情通常是不安全的,除非你使用编译器扩展来确保你反序列化的任何用户定义类型都没有填充。

答案 2 :(得分:0)

c ++中的C样式转换不是一个好主意,因为你经过了阻止你删除const或任意更改类型的检查。如果你想使代码按原样运行,首先需要const_cast然后reinterpret_cast,但真的尝试避免const转换。要使用reinterpret_cast避免警告,只需声明为const T*

答案 3 :(得分:0)

坚持使用C ++演员。 reinterpret_cast没有工作的原因是你扔掉了constness,这并不酷;你必须使用const_cast,你就不应该这样做。 C演员忽略了这一点。

话虽如此,你想在这里实现什么?您已经有效地转换为char数组和memcpy而没有带来的效率。

答案 4 :(得分:0)

很抱歉在这里发出声响,但你的代码在几个方面被破坏了,而且这些代码只是其中之一。关于转换,只要你使用转换from / to vector就不仅仅是一个简单的int或者需要一个构造函数,它就会失败。无论如何,从char const*void const*T const*的两步转换很遗憾是必要的。

现在,其他问题:

  • 使用零大小的字符串尝试整个事情。现在这应该完全回答你的实际问题:不,它不安全。
  • 您正在从DeSerialize<char const*>()返回指向char的指针。这个指针指向由给定向量拥有的内存,该值由值传递,并且从该函数返回后不再存在!它似乎很有运气。
  • 即使您设法以某种方式从函数返回char const*,也要考虑现在拥有该内存的人。关键是这个拥有者还必须释放内存。请考虑使用std::string并使char const*变体不使用模板的特化进行编译。
  • 一般来说,如果您认真对待此代码,请开始添加单元测试。它可能会减慢您的速度,但在您离开时可以避免错误,从而节省整体时间。搜索&#34;测试驱动的开发&#34;。
  • 没有什么可以确保字符串是NUL终止的。
  • 不要使用new / delete,除非你必须,更喜欢&#34; plain&#34;堆栈变量。如果这样做,请在异常的情况下(从push_back())正确释放内存。使用auto_ptr(C ++ 98)或unique_ptr(C ++ 11)确保正确释放内存。