构造函数对象分配是否泄漏内存

时间:2017-07-28 22:25:47

标签: c++ memory-leaks

说我有一个像这样的简单类:


class MyObj
{
char* myPtr;
public: 
    MyObj()
    {
        myPtr = malloc(30);
    }
    ~MyObj()
    {
        free(myPtr);
    }
} 

class TestObject
{
    MyObj _myObj;

public:
    TestObject(MyObj myObj) 
    {
        _myObj = myObj;
    }
};

这会泄漏内存吗?我的理由是,在构造函数运行时,TestObject中已经包含了一个MyObj实例,所以在释放内存之前不会吹掉myPtr吗?分配给本地对象是否会调用要替换的对象的析构函数?如果在构造函数中直接赋值,编译器是否会优化对象实例变量的赋值?我来自C#,只是通过声明一个引用类型变量来自动初始化一个对象,所以这让我很困惑。

谢谢!

1 个答案:

答案 0 :(得分:3)

  

这会泄漏内存吗?

的。 myObj的赋值将调用默认的复制赋值运算符,因为您没有提供覆盖。因此,将执行逐个成员的副本,并使用分配源中的myPtr实例覆盖分配目标的myPtr实例。引入了两个问题,这些问题在违反Rule of Three/Five/Zero的一个或多个部分时经常遇到:

  1. 您丢失了分配目标中的原始myPtr内容。因此,该指针唯一引用的原始内存被泄露。
  2. 您现在在两个myPtr成员中共享相同的指针值:源分配操作的目标。
  3. 后者尤其令人不安,因为myObjTestObject构造函数中完成赋值后立即离开作用域。这样做,myObj将被销毁,并由此释放myPtr myObj。此外,MyObj已通过 传递 ,而不是引用,因此隐式副本可能已经发生(由于右值移动语义)。因此,三个 myPtr对象可能正在提升所有引用相同内存free,并且只要一个人释放它,其余的就会在不知不觉中吊起悬空指针。对这些指针的任何解除引用或std::vector<char>将调用未定义的行为

      

    分配给本地对象是否会调用要替换的对象的析构函数?

    只能调用析构函数来生活他们的同名。即,只有当对象被销毁时才会调用它们(尽管手动调用析构函数来放置新语义)。除非引入临时代码,否则复制分配不会这样做,而且代码中的情况并非如此。

      

    如果对象实例变量在构造函数中直接赋值,编译器是否会优化它的分配?

    不,但member initialization list可以在这方面提供帮助。

    现代C ++编程技术经常使用RAII来完成您似乎尝试的各种方式,具体取决于您真正想要实现的目标。

    每个实例的唯一数据

    如果目标是每个实例的唯一动态数据,则可以使用std::string或简单地class MyObj { std::vector<char> myData; public: MyObj() : myData(30) { } } class TestObject { MyObj _myObj; public: TestObject(MyObj myObj) : _myObj(std::move(myObj)) { } }; 轻松完成此操作,具体取决于基本需求。两者都是RAII数据类型,通常足以满足动态内存管理需求。

    MyObj

    这消除了对TestObject中的析构函数的需要,并利用移动语义以及MyObj构造函数中的上述成员初始化列表。 char的所有实例都会提升MyObj的不同向量。 TestObjectclass MyObj { std::shared_ptr<char> myPtr; public: MyObj() : myPtr(new char[30]) { } }; class TestObject { MyObj _myObj; public: TestObject(MyObj myObj) : _myObj(std::move(myObj)) { } }; 的所有分配操作都适用于默认实现。

    作业共享内存

    不太可能你想要这个,但它不是那么可行:

    myPtr

    类似的代码,但不同的成员类型。现在charmyPtr数组的shared pointer。对不同new的任何分配都会加入共享列表。简而言之,赋值意味着对象引用相同的数据,引用计数确保最后的人员扫描混乱。

    注意:使用这样的共享指针可能会发生内存泄漏,因为select text,date_created from item_comment where MONTH( date_created ) = 12 order by rand() limit 1000 可能会成功,但共享指针的共享数据块可能会抛出异常。这在C ++ 17中得到解决,  其中std::make_shared支持数组分配

    这些只是做一些你可能想要完成的事情的方法。我们建议您在提供的链接和本网站上阅读Rule of Three/Five/ZeroRAII概念。有很多例子可能会回答你可能有的其他问题。