使用本地对象

时间:2016-01-26 12:24:13

标签: c++ pointers vector

我想创建一个具有不同类型A对象的矢量但是......

此代码抛出此异常:      free():无效指针:0x0000000000401757 ***

#include <vector>

class A
{
    char * elem;

public:
    A()
    {
        elem = new char[10];
    }
    void setA(char* name)
    {
        elem = name;
    }
    ~A()
    {
        delete[] elem;
    }

};

int main(int argc, char **argv)
{
    std::vector<A> v_a;
    for (int i = 0; i < 10; ++i)
    {
        A m_a;
        m_a.setA("jaja");
        v_a.push_back(m_a);

    }
}

为什么会这样?如何实施正确的解决方案?

2 个答案:

答案 0 :(得分:2)

调用setA(...)时,您没有复制字符串的数据,而是复制本地字符串的地址。 (查看cplusplus.com关于指针和字符串文字的内容)

setA(...)调用结束的块结束后,此字符串超出范围,因此之后地址无效

所以你试图从中分配的析构函数中的释放内存,并且此时已经很久了......

更新建议1:于2016年1月27日添加

  • 在将A的实例推送到std::vector时,还需要考虑复制ctor的需要。遵守Rule of three我也添加了一个复制赋值运算符。

    如果Rule of five

  • ,请参阅
  • 妥善处理可能'错误'大小的字符串

    #include <cstring>
    
    ...
    
    /// copy ctor
    A(const A& other) :
            elem(new char[10])
    {
        // prevent duplicate code
        setA(other.elem);
    }
    
    /// copy assignment operator
    A& operator=(const A& other)
    {
        // prevent duplicate code
        setA(other.elem);
    
        return *this;
    }
    
    /// set A's name (which is truncated to 9 characters if necessary)
    void setA(const char* name)
    {
        // copy first 9 chars from name
        // if there's fewer chars: elem is padded with zeros
        std::strncpy(elem, name, 9);
    
        // add null character / zero (string delimiter) manually
        // this is necessary for cases where name has 10 or more chars
        elem[9] = 0;
    }
    

(已作废)建议1:继续使用c样式字符串

  • 显式复制传递的字符串的数据(您需要这样做以使方法有效)
  • setA(...)的参数列表中添加一个长度指示器(这是可选的,您还可以计算出方法内部字符串的长度......)

    #include <cstring>
    
    ...
    
    void setA(char* name, size_t length)
    {
        std::memcpy(elem, name, length);
    }
    

建议2:切换到c ++样式字符串

  • 使用std::string(我更喜欢这个版本,因为它可以节省内存处理并且非常直观地读取)

    #include <string>
    
    class A
    {
        std::string elem;
    
    public:
        A(){}
    
        void setA(std::string name)
        {
            elem = name;
        }
    
        ~A(){}
    };
    

答案 1 :(得分:1)

修改elem的值,该值是指向免费商店中分配的内存区域的指针。现在,elem指向字符串文字,不适用于deletedelete[]
不在免费商店中的delete对象是未定义的行为。你的析构函数会尝试它。