Are there any valid use cases to use new and delete, raw pointers or c-style arrays with modern C++?

前端 未结 19 1174
梦谈多话
梦谈多话 2020-11-22 07:20

Here\'s a notable video (Stop teaching C) about that paradigm change to take in teaching the c++ language.

And an also notable blog post

19条回答
  •  日久生厌
    2020-11-22 07:59

    Some APIs might expect you to create objects with new but will take over ownership of the object. The Qt library for example has a parent-child model where the parent deletes its children. If you use a smart pointer, you are going to run into double-deletion issues if you're not careful.

    Example:

    {
        // parentWidget has no parent.
        QWidget parentWidget(nullptr);
    
        // childWidget is created with parentWidget as parent.
        auto childWidget = new QWidget(&parentWidget);
    }
    // At this point, parentWidget is destroyed and it deletes childWidget
    // automatically.
    

    In this particular example, you can still use a smart pointer and it will be fine:

    {
        QWidget parentWidget(nullptr);
        auto childWidget = std::make_unique(&parentWidget);
    }
    

    because objects are destroyed in reverse order of declaration. unique_ptr will delete childWidget first, which will make childWidget unregister itself from parentWidget and thus avoid double-deletion. However, most of the time you don't have that neatness. There are many situations where the parent will be destroyed first, and in those cases, the children will get deleted twice.

    In the above case, we own the parent in that scope, and thus have full control of the situation. In other cases, the parent might not be hours, but we're handing ownership of our child widget to that parent, which lives somewhere else.

    You might be thinking that to solve this, you just have to avoid the parent-child model and create all your widgets on the stack and without a parent:

    QWidget childWidget(nullptr);
    

    or with a smart pointer and without a parent:

    auto childWidget = std::make_unique(nullptr);
    

    However, this will blow up in your face too, since once you start using the widget, it might get re-parented behind your back. Once another object becomes the parent, you get double-deletion when using unique_ptr, and stack deletion when creating it on the stack.

    The easiest way to work with this is to use new. Anything else is either inviting trouble, or more work, or both.

    Such APIs can be found in modern, non-deprecated software (like Qt), and have been developed years ago, long before smart pointers were a thing. They cannot be changed easily since that would break people's existing code.

提交回复
热议问题