为侧面项目滚动我自己的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...
};
我最好使用C ++ 98样式和语义并自己处理它。显然我不希望跨接口边界传递智能指针(即AddControl),但我不想负责处理控件的生命周期。
此外,使用new Button("testButton")
感觉很脏。
答案 0 :(得分:1)
提醒您,如果您只是保证您不会发布在与主要可执行文件不同的编译器/版本/平台上编译的DLL,则可以规避ABI问题。
无论如何,关于您的界面设计:
void AddControl(Control& control) {
mControls.emplace_back(&control)
}
你在这里遇到了问题,因为
Control
是多态的(或者至少看起来基于你提供的代码),这意味着你必须通过引用或指针传递来获得一个完整的&#34;对象,但这是我围绕这个问题设计的方法:
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 MyFinanceApp : public Application {
public:
MyFinanceApp() : mMainWindow(make_unique<Window>()) {
mMainWindow->AddControl(std::make_unique<Button>("testButton"));
}
private:
std::unique_ptr<Window> mMainWindow;
};
请注意,这并不一定会阻止用户做一些愚蠢的事情,比如
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!
......但是,首先没有什么可以阻止他们这样做。
另一种选择是拥有一个&#34;工厂&#34;与控件相关联。我们首先需要对AddControl
进行修改:
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;
}
};
然后,您只需更改所有Control
子类上的访问修饰符,以便不允许最终用户程序员直接访问其构造函数。这样的事情可能就足够了:
class Button : public Control {
/*...*/
protected:
Button() {/*...*/}
Button(std::string text) {/*...*/}
friend class ControlFactory; //Allows ControlFactory to access, even though access is protected.
};
然后你的用户会在它们的末尾存储引用,这比指针更安全,但它确实意味着你需要保证那些引用永远不会超过应用程序本身。