Frage

For example, suppose I have a class to create a button with specific styles common to my app:

class ButtonFactory{
public:
  static Button* createAppButton(std::string st,int font size){
    Button* b=new Button();
    //b->setColor();b->setText()...;b->playAnimation(...);
    return b;
  }
}

at other class

this->b=ButtonFactory::createAppButton("OK",20);
.
.
.
//delete it at destructor
delete b;

However, I feel uncomfortable that the 'new' and 'delete' are not at the same class. So my question is, should I also create a delete method in the ButtonFactory:

static void deleteAppButton(Button* b){
  delete b;
}
.
.
.
ButtonFactory::deleteAppButton(this->b);

instead of delete b by keywords directly?

War es hilfreich?

Lösung

  • With manual resource management, this is a must. You definitely want to provide destructor method. C is a good illustration for this, literally every allocator has accompanying destructor.
  • With managed memory Button is supposed to implement Disposable interface, which manages destruction (compiler assisted). Java and C# are famous for their resource leaks caused by misuse of Disposables.
  • C++ and Rust (RAII resource management) suggest to return an object that manages it's own lifetime. RAII moves responsibility for resource management from a new owner to allocating code, separating ownership and resource management concerns.

In this case a method would probably return unique_ptr<Button>. Smart pointer could include a custom destructor, if default one is not suitable in future.

Other approaches may be justified, but there is nothing indicating that in your example. Please, explain, why do you use raw pointers?

Andere Tipps

The object of the class should be able to take care of its own cleanup. This is a good practice.

If you follow your approach with ButtonFactory::deleteAppButton(this->b), then the calling code has to know that the object of the class Button has to be disposed of in a special way. This increases the risk that somebody will forget to call the ButtonFactory::deleteAppButton(...).

Furthermore...

Imagine a Button class that can't take care of doing all of the destruction by itself, and needs assistance from another class. (For example, some resource for the Button objects come from a pool, and have to return to the pool. The pool management is done by a separate class.) Then the Button class should call the pool manager object in the destructor. To be able to do that, the Button class should keep a pointer to the pool manager object. The calling code should only do delete b.

This is very language-dependent.

What are you writing is good old wizdom of C coding. Because

  • C does not have any standard way of cleanup
  • C is used to produce highly portable shared libraries, and sometimes there is literally no "runtime" code shared by a library you use and rest of the application

So it is customary for C each API to have its own cleanup functions for own types, like curl_multi_cleanup()

For C++ situation is a bit different. There is a standard way to delete objects, moreover, you do not usually delete them explicitely, instead using RAII and destructors to do it. So for idiomatic C++ you should make object deletable with simple delete. Also, portability requirements for C++ code is much less strict - you usually expect that a library you use and code which uses it are build with same compiler and standard library and other dependencies.

The PURPOSE of a factory is to abstract away the choices of how to create a particular instance. This generally means, selecting what extra information to stick into it, and it subtype. If it implies some special handling of the deletion of the object, that should generally be injected into the smartpointer itself (in C++ deleter or Button or subclass destructor).

Factories have NOTHING whatsoever to do with object lifetime.

As other have mentioned, managing object lifetime is somewhat language dependent. Since you seem to be using C++ (and since IMHO that has the best/most power over this aspect of programming) - you would be well served to consider using smart pointers to manage the lifetime of your objects.

For example, I would use:

class ButtonFactory{
public:
  static shared_ptr<Button> createAppButton(std::string st,int font size){
    shared_ptr<Button>  = make_shared<Button> ();
    //b->setColor();b->setText()...;b->playAnimation(...);
    return b;
  }
}

Note - when you do this - its important to store an explicit copy of the smart pointer someplace, because when the last reference to the smart pointer goes away, the object will be deleted.

Lizenziert unter: CC-BY-SA mit Zuschreibung
scroll top