1

I am writing a C++ program for Linux. I use many low-level libraries such as XLib, FontConfig, Xft etc. They are all written in pure C, and in some places in my code I have this annoying problem:

I wrap C structures in RAII-friendly classes, where resources are allocated in constructors and freed in destructors. Freeing most of these resources is not just calling free(), special library functions should be used instead (::XftFontClose(), ::FcPatternDestroy() etc), so I don't see benefits of using smart pointers. Instead, I keep read-only raw pointers to library resources inside my classes and provide getter functions returning constant pointers to these resources so that they are unable to be modified outside of the classes that own them.

For example, I have a class containing a sorted list of system fonts, and I can ask this class to find and open the best font that can be used to draw a specific character:

const ::XftFont* FontHandler::findBestFont(wchar_t character);

The callers should not be able to modify the underlying object pointed to by the returned pointer, this is the task of the class' methods/destructor.

The problem is that, most of the functions I want to pass the returned pointer to look like this:

void
XftDrawStringUtf8
               (XftDraw         *d,
                XRenderColor    *color,
                XftFont         *font, // It is not const
                int             x,
                int             y,
                XftChar8        *string,
                int             len);

As you can see, even if the function does not need to change the data pointed to, the pointer is not const, and the only way to make it work is to use const_cast, which is never recommended, as far as I know.

This is just a single example, but there are many such issues in the real code.

I wonder, why are these legacy libraries built in such a way? Why don't they use const pointers when they actually should be const? And what is the best way to deal with such problems?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Alexey104
  • 969
  • 1
  • 5
  • 17
  • 8
    it's actually pretty much the reason to use `const_cast` – apple apple Aug 11 '22 at 14:09
  • 2
    `const_cast` is fine here. `const_cast` is really only an issue when the thing you are casting away const on is actually const. Your underlying data isn't actually const so no issue there. – NathanOliver Aug 11 '22 at 14:10
  • 4
    Also re: "Special library functions should be used instead...so I don't see benefits of using smart pointers": You may be interested that you can use custom deleter functions with [std::unique_ptr](https://stackoverflow.com/questions/19053351/how-do-i-use-a-custom-deleter-with-a-stdunique-ptr-member) and [std::shared_ptr](https://stackoverflow.com/questions/60568363/shared-ptr-custom-deleter) – Nathan Pierson Aug 11 '22 at 14:15
  • 1
    also note that the `const` doesn't propagate through pointer, so the user actually *can* modify the object. (according to [this](https://www.x.org/archive/X11R7.5/doc/man/man3/Xft.3.html) it do have pointer member) – apple apple Aug 11 '22 at 14:24
  • 1
    Also Windows API! – Spencer Aug 11 '22 at 14:26
  • 1
    Using `const_cast` is only an issue if you (1) cast away `const`ness on something that cannot be not be modified AND (2) code which receives the non-`const` pointer/reference then actually modifies those objects. From what you describe, both conditions are met. You may want to set things up so you can verify that is so - for example, if you update the library, it may pay to confirm that the new version still plays by the same rules. – Peter Aug 11 '22 at 16:22
  • 1
    You can still use smart pointers with custom deletion semantics, see: https://stackoverflow.com/questions/26360916/using-custom-deleter-with-unique-ptr – Chad Aug 11 '22 at 17:39

1 Answers1

2

Is it necessarily bad to use const_cast when working with legacy libraries?

No.

It's generally bad to design code that requires a lot of const_cast, because it suggests you haven't thought very carefully about mutability.

You're using libraries that were written before const-correctness was much considered, and their design shortfalls are not your fault. Adapting to them is an entirely appropriate use of const_cast.

Freeing most of these resources is not just calling free(), special library functions should be used instead(::XftFontClose(), ::FcPatternDestroy() etc.,) so I don't see benefits of using smart pointers

You know you can use smart pointers with custom deleters, right? The benefit - that you don't have to implement five special methods in each class - is still there.

At most, consider writing a rule-of-zero wrapper type storing a std::unique_ptr (or std::shared_ptr, or whatever) with a custom deleter. It's a lot less typing, and way fewer opportunities for annoying bugs.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Useless
  • 64,155
  • 6
  • 88
  • 132