【问题标题】:Why push_back doesn't push a copy of the source obj?为什么 push_back 不推送源 obj 的副本?
【发布时间】:2014-09-01 14:51:11
【问题描述】:

我的代码如下:

class CDemo {
public:
    CDemo()
        : str(NULL){

          };
    ~CDemo() {
        if (str)
            delete[] str;
    };
    char* str;
};

void testVector() {
    CDemo c;
    c.str = new char[32];
    strcpy(c.str, "abcdef");
    vector<CDemo>* v = new vector<CDemo>();
    v->push_back(c);
    delete (v);
    return;
}

我知道这是一个会报告运行时错误的代码,因为我没有显式定义复制构造函数,所以,当testVector 返回时,成员字段str 将被释放两次,从而报告一个错误。但让我感到困惑的是,当我调试到该行时:delete(v),Visual Studio 快捷方式如下:

我认为函数push_back会导致对象c的default copy constructor的调用,所以,在push_back返回之后,向量v的元素应该是与c不同的对象,但从调试手表来看,我发现它们是相同的address:0x00318100。是否证明它们实际上是同一个对象? 谁能解释一下?

【问题讨论】:

  • 它确实推送对象的副本。您有两个相同指针的副本。
  • 但调试器显示存储在str 中的地址。这正是你自己说的你期望是一样的。
  • CDemo的默认复制构造函数复制的是str的指针值,而不是指向的数据。
  • 这是 char 字符串的地址,因此它们相同是完全正常的
  • 看到汉字,笑死我了。

标签: c++ vector copy-constructor push-back


【解决方案1】:

它确实推送了CDemo 对象的副本。

但是,两个副本都包含相同的 str 指针值。这就是您在调试器中看到的内容,这就是为什么两者都尝试删除同一个数组的原因。

要修复双重删除,要么

  • 使用std::string为你正确管理内存;或
  • 根据Rule of Three,仔细实现复制构造函数和复制赋值运算符,以正确复制字符串内容,而不是指针。

除非您正在自学如何管理动态内存,或者有非常特殊的要求,否则请使用std::string。一般来说,除非你真的需要,否则不要使用new - 特别是,没有理由动态分配向量。

【讨论】:

    【解决方案2】:

    您正在查看char* 地址,该地址在设置后被“原样”复制,而不是对象的地址。

    指针的地址可能不同(您可以通过启用代码反汇编模式并查看所涉及的指针和/或查看堆栈和内存转储来验证这一点)但它们确实指向相同的位置。

    【讨论】:

      【解决方案3】:

      “c”可能是堆栈分配的:

      CDemo c ;
      

      但是你将一个堆分配的指针推入“c”:

      c.str=new char[32];
      

      因此,您可以添加另一个构造函数来创建自己的堆分配内容副本:

      CDemo(const char* src) :str(new char[strlen(src)+1]) {
          strcpy(str, src);
      };
      

      比这样使用它:

      vector<CDemo> v;
      v.push_back(new CDemo("abcdef"));
      

      【讨论】:

        猜你喜欢
        • 2014-02-16
        • 1970-01-01
        • 1970-01-01
        • 2017-05-13
        • 1970-01-01
        • 2021-03-11
        • 1970-01-01
        • 2014-08-05
        • 2014-07-06
        相关资源
        最近更新 更多