Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: pointers in Component


This question is answered.


Permlink Replies: 2 - Last Post: Dec 14, 2017 2:12 PM Last Post By: Wei Sun Threads: [ Previous | Next ]
Wei Sun

Posts: 8
Registered: 8/14/17
pointers in Component  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 13, 2017 11:11 PM
Hello,

I have a few questions about writing VCL Components for Win32 applications - specifically - how do we deal with ownership of pointers in component classes, shown as below?

1. Is making TMyGraphicControl own the member font_ correct practice?

2. If the component must own the pointers, is it safe to return raw pointer like TMyGraphicControl::GetFont() and TMyGraphicControl::Font?

3. In TMyGraphicControl::Paint(), is it safe to pass raw pointer to TCanvas::Font?

class TMyGraphicControl : public TGraphicControl
{
  std::unique_ptr<Vcl::Graphics::TFont> font_;
  Vcl::Graphics::TFont* __fastcall GetFont() {
    return font_.get(); //is it safe to return raw pointer like this or shall I return const Vcl::Graphics::TFont*?
  }
  void __fastcall SetFont(Vcl::Graphics::TFont* Value) {
    font_.reset(Value); //is it safe to take ownership of the passed pointer???
    Invalidate();
  }
protected:
  virtual void __fastcall Paint(void) {
    Canvas->Font = GetFont(); //is it safe to pass raw pointer here???
    //the rest of implementation
  }
public:
  __fastcall TMyGraphicControl(TComponent* Owner) : TGraphicControl(Owner),
    font_(new Vcl::Graphics::TFont()) {
 
  }
__published:
  __property Vcl::Graphics::TFont* Font = {read = GetFont, write = WriteFont};
}
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: pointers in Component
Correct
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 14, 2017 10:47 AM   in response to: Wei Sun in response to: Wei Sun
Wei Sun wrote:

I have a few questions about writing VCL Components for Win32
applications - specifically - how do we deal with ownership of
pointers in component classes, shown as below?

If the component creates an inner object, it should own it and free it
in the destructor. Any property you define to access the object
pointer should be read-only, or have a setter that calls the object's
Assign() method if it is derived from TPersistent.

If the component accepts a pointer to an external object, it should not
take ownership. If the object is derived from TComponent, call its
FreeNotification() method so you can be notified (by having your
component override its virtual Notification() method) if the object is
freed while your component is still pointing at it. NULL out your
pointer if notified. If changing the object pointer to point at a new
object, call RemoveFreeNotification() on the previous object. And make
sure you check for NULL any time you want to access the object.

1. Is making TMyGraphicControl own the member font_ correct practice?

Yes, since the component is creating the TFont object, so it is
responsible for freeing it. You should also be assigning an OnChange
event handler to the TFont so you can call Invalidate() when any of the
font's property values change. Don't call it in your Font property
setter.

2. If the component must own the pointers, is it safe to return raw
pointer like TMyGraphicControl::GetFont() and TMyGraphicControl::Font?

Yes, as long as noone else tries to take ownership of the pointer. Any
class/component that follows the rules above will be safe.

3. In TMyGraphicControl::Paint(), is it safe to pass raw pointer to
TCanvas::Font?

Yes, because the TCanvas::Font property has a setter that calls
TFont::Assign() on the Canvas's internal TFont object. It does not
take ownership of the pointer you pass to it. It copies the values of
the font's sub-properties instead.

void __fastcall SetFont(Vcl::Graphics::TFont* Value) {
font_.reset(Value); //is it safe to take ownership of the passed
pointer???
Invalidate();
}

NO! Call Assign() to copy the sub-property values instead:

Canvas->Font = GetFont(); //is it safe to pass raw pointer here???

Yes.

With that said, your component should look more like this:

class TMyGraphicControl : public TGraphicControl
{
private:
    std::unique_ptr<Vcl::Graphics::TFont> font_;
 
    void __fastcall FontChanged(TObject *Sender)
    {
        Invalidate();
    }
 
    Vcl::Graphics::TFont* __fastcall GetFont()
    {
        return font_.get();
    }
 
    void __fastcall SetFont(Vcl::Graphics::TFont* Value)
    {
        font_->Assign(Value);
    }
 
protected:
    virtual void __fastcall Paint(void)
    {
        Canvas->Font = Font;
        // effectively Canvas->Font->Assign(Font) ...
 
        //the rest of implementation
    }
 
public:
    __fastcall TMyGraphicControl(TComponent* Owner)
        : TGraphicControl(Owner), font_(new Vcl::Graphics::TFont())
    {
        font_->OnChange = &FontChanged;
    }
 
__published:
    __property Vcl::Graphics::TFont* Font = {read = GetFont, write =
SetFont};
}


However, TGraphicControl already has a Font property inherited from
TControl, so you shouldn't be re-defining the Font property in your
component at all (but, you should follow the above logic if you need to
define additional object-based properties). Promote the existing Font
property instead, eg:

class TMyGraphicControl : public TGraphicControl
{
protected:
    virtual void __fastcall Paint(void)
    {
        Canvas->Font = Font;
        // effectively Canvas->Font->Assign(Font) ...
 
        //the rest of implementation
    }
 
public:
    __fastcall TMyGraphicControl(TComponent* Owner)
        : TGraphicControl(Owner)
    {
    }
 
__published:
    __property Font; // <-- that is all you need!
};

--
Remy Lebeau (TeamB)

Wei Sun

Posts: 8
Registered: 8/14/17
Re: pointers in Component  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 14, 2017 2:12 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thanks. That answer all of my questions. Using TFont as an example was the only class name that crossed my mind to deliberate my questions while trying to shorten the sample codes in question as much as possible.
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02