C++ 库管理对象的生存期,使用智能指针还是原始指针?
为一个辅助项目滚动我自己的GUI库。重构以使用智能指针;然而,我遇到了一个问题 我知道,出于明显的原因,您不希望跨DLL边界使用智能指针。但我觉得在应用程序代码中使用“new”有点脏。见下文: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
// 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.
};