C++ 库管理对象的生存期,使用智能指针还是原始指针?

C++ 库管理对象的生存期,使用智能指针还是原始指针?,c++,oop,c++14,C++,Oop,C++14,为一个辅助项目滚动我自己的GUI库。重构以使用智能指针;然而,我遇到了一个问题 我知道,出于明显的原因,您不希望跨DLL边界使用智能指针。但我觉得在应用程序代码中使用“new”有点脏。见下文: // MYFINANCEAPP.H class MyFinanceApp : public Application { MyFinanceApp() : mMainWindow(make_unique<Window>()) { mMainWindow->AddControl(*(n

为一个辅助项目滚动我自己的GUI库。重构以使用智能指针;然而,我遇到了一个问题

我知道,出于明显的原因,您不希望跨DLL边界使用智能指针。但我觉得在应用程序代码中使用“new”有点脏。见下文:

// MYFINANCEAPP.H
class MyFinanceApp : public Application
{

MyFinanceApp() : mMainWindow(make_unique<Window>())
{
  mMainWindow->AddControl(*(new Button("testButton")));
}

private:
  std::unique_ptr<Window> mMainWindow;
};

// WINDOW.H
class Window
{
public:
  void AddControl(Control& control)  //QUESTION: HOW DO I GET SMART POINTER HERE???
  {
    mControls.emplace_back(&control)
  }
private:
  std::vector<std::unique_ptr<Control>> mControls;  //Want to use smart pointers so I am not responsible for managing...
};
//MYFINANCEAPP.H
MyFinanceApp类:公共应用程序
{
MyFinanceApp():mMainWindow(使_唯一())
{
mMainWindow->AddControl(*(新按钮(“测试按钮”));
}
私人:
std::唯一的\u ptr mMainWindow;
};
//窗户
类窗口
{
公众:
void AddControl(Control&Control)//问题:如何在这里获取智能指针???
{
mControls.emplace_back(&control)
}
私人:
std::vector mControls;//希望使用智能指针,因此我不负责管理。。。
};
我最好使用C++98的风格和语义并自己处理它。显然,我不想跨接口边界传递智能指针(即AddControl),但我不想负责处理控件的生存期


此外,使用
new按钮(“testButton”)
时,我会感到非常不舒服。如果您只需保证不会发布在与主可执行文件不同的编译器/版本/平台上编译的DLL,就可以避免ABI问题

无论如何,关于您的界面设计:

void AddControl(Control& control) {
    mControls.emplace_back(&control)
}
你这里有个问题,因为

  • 控件
    是多态的(或者至少看起来是基于您提供的代码),这意味着您必须通过引用或指针传递才能获得“完整”对象,但是
  • 您不希望公开一个界面,用户必须在将原始指针传递给应用程序之前维护原始指针,即使是短暂的
以下是我将如何围绕这个问题进行设计:

class Window {
public:
    void AddControl(std::unique_ptr<Control> control) {//Note we're passing by value!
        mControls.emplace_back(std::move(control));
    }
private:
    std::vector<std::unique_ptr<Control>> mControls;
};
然后,您只需要更改所有
控件
子类上的访问修饰符,以不允许最终用户程序员直接访问其构造函数。这样的事情可能就足够了:

class Button : public Control {
    /*...*/
protected:
    Button() {/*...*/}
    Button(std::string text) {/*...*/}
    friend class ControlFactory; //Allows ControlFactory to access, even though access is protected.
};

然后,您的用户将在其端存储引用,这比指针更安全,尽管这确实意味着您需要保证这些引用永远不会超过应用程序本身。

这些“明显的原因”是什么?单独的堆会影响动态分配的对象,不管它们是由智能指针还是原始指针拥有…@Quentin我想他是在谈论ABI问题。使用动态库,C语言接口更容易,因为C abi定义良好,而C++ abi不是。@ NEFAS是正确的。@昆廷,是的,我重新阅读了这个问题,但并不十分清楚。你不能半途而废:或者你暴露C接口(没有智能指针,没有类,…)(安全),或者你可以暴露C++接口(然后你可以使用智能指针)(如果需要我正确地理解你的问题:需要编译特定的编译器,编译器版本…):1。您的客户端接口必须尽可能通用。2.“在应用程序代码中使用“新”会让我感觉脏”会感觉更好吗?3.客户端接口中的stl:如果您的客户端使用不同的stl实现,该怎么办?
std::unique_ptr<Window> window_ptr = std::make_Unique<Window>();
Button * button = new Button("This won't be properly deleted!");
window_ptr->AddControl(std::unique_ptr<Button>{button});
delete button; //Whoops!
Control & AddControl(std::unique_ptr<Control> control) {
    mControls.emplace_back(std::move(control));
    return *mControls.back();
}

struct ControlFactory {
    static Button & create_button(Window & window, std::string button_text) {
        std::unique_ptr<Button> button_ptr = std::make_unique<Button>(button_text);
        Button & ref = *button_ptr;
        window.AddControl(std::move(button_ptr));
        //ref will NOT be invalidated, because the object will still exist in memory,
        //in the same location in memory as before. Only the unique_ptr will have changed.
        return ref;
    }
};
class Button : public Control {
    /*...*/
protected:
    Button() {/*...*/}
    Button(std::string text) {/*...*/}
    friend class ControlFactory; //Allows ControlFactory to access, even though access is protected.
};