【问题标题】:How does an undefined new operator lead to undefined behaviour in C++?未定义的 new 运算符如何导致 C++ 中的未定义行为?
【发布时间】:2019-12-18 00:48:20
【问题描述】:

这里有一个 C++ 代码:

#include <iostream>
#include <map>
#include <string>
#include <cstdlib>

using namespace std;

class Person {
    private:
        int year;
        Person(const Person& pers);
    public:
        Person(int y): year(y)
        { cout << "Default constructor" << endl;}

        ~Person()
        {
            cout << "Destructor " << endl;
        }

        int get_year() const
        {
            return year;
        }
};


int main()
{
    map<string, Person*> test;
    test.insert(pair<string, Person*>("ini_1", new Person(2)));
    return 0;
}

输出

Default constructor
  1. 从输出中,我想知道,如何删除给定new Person(2)test 映射的值,而无需像先编码一样
Person* per = new Person(2)
test.insert(pair<string, Person*>("ini_1", per));

delete per;
  1. 没有先这样定义
Person* per = new Person(2)
test.insert(pair<string, Person*>("ini_1", per));

它会导致未定义的行为吗?您能否描述未定义行为的更多细节?尤其是它是如何存在于内存中的?谢谢。

  1. 如果不正确,我可以这样使用Person 代替new Person 吗?它会导致任何未定义的行为吗?
#include <iostream>
#include <map>
#include <string>
#include <cstdlib>

using namespace std;

class Person {
    private:
        int year;

    public:
        Person(int y): year(y)
        { cout << "constructor" << endl;}

        Person(const Person& pers)
        {
            cout << "copy constructor" << endl;
        }
        ~Person()
        {
            cout << "Destructor " << endl;
        }

        int get_year() const
        {
            return year;
        }
};


int main()
{
    map<string, Person> test;

    test.insert(pair<string, Person>("ini_1", Person(2)));

    return 0;
}

输出:

constructor
copy constructor
copy constructor
Destructor
Destructor
Destructor
  1. 我不明白为什么构造函数运行一次而复制构造函数运行两次。你能解释一下他们发生在哪里吗?

谢谢。

【问题讨论】:

  • 听起来你可以使用good C++ book
  • 我在这里看不到任何未定义的行为。在指针情况下,您的析构函数不会运行,但那是因为没有delete。您可以通过使用智能指针而不是原始指针来纠正此问题。但是在这里使用值而不是指针并没有错。..
  • @wangmyde 你不能测试未定义的行为,你必须知道。而且C++中没有“新指针”或“未定义指针”之类的东西,如果你想被理解,你应该使用通用术语。
  • 在 4. 你创建了 Person 临时,它被复制以构造 pair&lt;&gt; 临时,并再次复制到插入函数中。
  • @wangmyde 这就像用doSomething(2); 而不是int i = 2; doSomething(i); - 也就是说,它没有任何区别。

标签: c++ new-operator heap-memory copy-constructor delete-operator


【解决方案1】:

从输出中,我可以看到析构函数没有运行。我想 知道,如何在不定义新指针的情况下删除它?

你声明了一个;指向 Person 的指针的映射

map<string, Person*> test;

因此,Person 类型的对象在此语句中只创建一次

test.insert(pair<string, Person*>("ini_1", new Person(2)));

进一步地图处理指针而不是对象。

您需要明确删除创建的对象。例如

for ( auto &item : test )
{
    delete item.second;
     item.second = nullptr;
}

如果您不删除分配的对象(或多个对象),则会出现内存泄漏。

我不明白为什么构造函数运行一次并复制 构造函数运行了两次。你能解释一下他们发生在哪里吗?

在此声明中

test.insert(pair<string, Person>("ini_1", Person(2)));

显式调用转换构造函数以创建 Person Person(2) 类型的对象。

然后调用Person类的拷贝构造函数来创建pair&lt;string, Person&gt;类型的对象。

最后,这个对象被复制到映射中,再次调用类型为 Person 的复制构造函数,用于该对中的第二个数据成员。

因此创建了三个对象并调用了对象的三个析构函数。

【讨论】:

  • 嗨,来自莫斯科的@Vlad。如果我使用test.insert(pair&lt;string, Person*&gt;("ini_1", new Person(2))); 而不是Person* per = new Person(2); test.insert(pair&lt;string, Person*&gt;("ini_1", per));,会导致未定义的行为吗?就像@h0r53所说的linkUsing new will almost certainly cause issues...
  • Using new will almost certainly cause issues, because the Person object will be stored on heap allocated memory. 1) Unless you call delete on the object, you'll have a memory leak. 2) Even if you do delete the object, the heap memory it allocated will be available for reuse, while your map still points to that memory. This is even worse. 对吗?
  • @wangmyde 在这种情况下都不会出现未定义的行为。如果您尝试使用本地声明的指针和存储在映射中的指针两次尝试删除内存,则可能会发生未定义的行为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-11
  • 2013-04-14
  • 1970-01-01
  • 2016-04-09
  • 2016-12-21
相关资源
最近更新 更多