在此示例中,删除数据变量最安全的方法是什么?

时间:2017-07-24 19:25:12

标签: c++ pointers

#include <iostream>
#include <cstdlib>

template<class To, class From>
To any_cast(From v)
{
    return static_cast<To>(static_cast<void*>(v));
}

class Something
{
public:
    template<class T>
    Something(T mydata);
    template<class T>
    void getData(T& t);
    ~Something();
private:
    unsigned char* data;
};

int main()
{
    {
        Something s(20.1);
        double ret = 0;
        s.getData(ret);
        std::cout << ret << std::endl;
    }
    return 0;
}

template<class T>
Something::Something(T mydata)
{
    data = new unsigned char[sizeof(mydata)];
    unsigned char* temdata = any_cast<unsigned char*>(&mydata);
    for (unsigned int i = 0; i < sizeof(mydata); i++)
    {
        data[i] = temdata[i];
    }
}

Something::~Something()
{
    delete[] data;
}

template<class T>
void Something::getData(T& t)
{
    T* tt = any_cast<T*>(data);
    t = *tt;
}

在上面的例子中,我获取一个对象并将其转换为unsigned char数组或字节数组。调用类解构函数后,我删除了这个变量。但是当我删除对象“data”时,我似乎一直在程序中遇到断点。

我认为这是因为它认为它是正常的char *并且正在寻找终止/ 0来表示字符串的结尾。

我知道,因为我正在分配数据,我需要对它进行DE分配,所以最安全的方法是什么。或者甚至是必要的?

考虑使用std :: vector并解决问题。但是如果对象分散在堆中,我不希望数据检索的性能受到影响。

我也试过了两个删除操作符。我得到了:

HEAP[test.exe]: Invalid address specified to RtlValidateHeap( 01380000, 04574468 )

任何一个出错。 (抱歉删除是一个错字)

代码从原始代码简化,因此我没有包含复制构造函数和ext。

在看到std :: any的用法后,我在测试环境中尝试了它:Here 而这似乎比我的想法更好。但现在我需要弄清楚如何让视觉工作室使用更高级别的编译器来访问c ++ 17特性= /

1 个答案:

答案 0 :(得分:0)

data是使用new[]分配的,因此您的析构函数需要调用delete[]而不是delete

您还缺少复制构造函数和复制赋值运算符,因此您的类不满足Rule of Three的要求,因此可能损坏内存,导致崩溃等。

尝试更像这样的事情:

#include <algorithm>

class Something
{
public:
    template<class T>
    Something(const T &mydata);

    Something(const Something &src);

    template<class T>
    void getData(T& t) const;

    ~Something();

    Something& operator=(const Something &src);

private:
    unsigned char* data;
    size_t data_size;
};

template<class T>
Something::Something(const T &mydata)
{
    data_size = sizeof(T);
    data = new unsigned char[data_size];
    const unsigned char* temp = reinterpret_cast<const unsigned char*>(&mydata);
    std::copy(temp, temp + data_size, data);
}

Something::Something(const Something &src)
{
    data_size = src.data_size;
    data = new unsigned char[data_size];
    std::copy(src.data, src.data + data_size, data);
}

Something::~Something()
{
    delete[] data;
}

template<class T>
void Something::getData(T& t) const
{
    const T* tt = reinterpret_cast<const T*>(data);
    t = *tt;
}

Something& Something::operator=(const Something &src)
{
    if (&src != this)
    {
        Something temp(src);
        std::swap(temp.data, data);
        std::swap(temp.data_size, data_size);
    }
    return *this;
}

最好使用std::vector而不是new[],让编译器和STL为您处理内存管理:

#include <algorithm>
#include <vector>

class Something
{
public:
    template<class T>
    Something(const T &mydata);

    Something(const Something &src);

    template<class T>
    void getData(T& t) const;

private:
    std::vector<unsigned char> data;
};

template<class T>
Something::Something(const T &mydata)
    : data(sizeof(T))
{
    const unsigned char* temp = reinterpret_cast<const unsigned char*>(&mydata);
    std::copy(temp, temp + sizeof(T), &data[0]);
}

Something::Something(const Something &src)
    : data(src.data)
{
}

template<class T>
void Something::getData(T& t) const
{
    const T* tt = reinterpret_cast<const T*>(&data[0]);
    t = *tt;
}

现在,正如所说,只要知道T是非POD类型时这种编码是不安全的,特别是如果它具有非平凡的构造函数和赋值运算符。

看起来您正在尝试实现与std::any类似的功能,这需要更多的工作来安全地支持非POD类型。