• Guessed (unregistered)

    the second parameters is a const reference (not a reference to a const value).

    I stopped reading there. There is no such thing as a const reference (were it legal, the syntax would be T &const ref). Both const T &ref and T const &ref declare a reference to a const T value.

  • (nodebb)

    This is an automatic memory leak; because we never trap the pointer, we never have the opportunity to release that memory

    Actually, we do still have a pointer to the object. It's masquerading as a reference, but it's still a pointer. We can, therefore, recover the pointer from the reference(1) (if the object we pass it to stores it as a reference somewhere), and use the recovered pointer to free the memory.

    Admittedly, you're probably right if you say that they don't do that, but you haven't show us the destruction paths of things, so we can't know that they don't haul out a bit of black magic to recover the pointer. They probably don't, but we can't know that from just this code.

    (1) &reference_variable is the address of the thing that reference_variable is a reference to...

  • (nodebb)

    Now, new QBatch_arithExpr(...) will also return a pointer, which we put in derefExpr. We then assert on that pointer, confirming that it isn't null. Which… it can't be.

    It most certainly can. And I don't mean "if you're still stuck on Visual C++ 6", either. If someone writes a class-specific operator new that returns nullptr on failure instead of throwing std::bad_alloc, you'll get a null back from a failed (by allocation failure) new call for that class.

    A constructor may fail and throw an exception, but you'll never get a null (now, I'm sure a sufficiently motivated programmer can mix nothrow and -fno-exceptions to get constructors to return null, but that's not happening here, and shouldn't happen anywhere)

    There's no need to get that elaborate, in fact. Just write a class-specific new or replace the global new and make your version return a null instead of throwing. For maximum "fun", have it catch exceptions from the constructor and return nullptr if they happen. Without logging.

  • (nodebb)

    C++ was one of the first "real" languages I learned, more than 25 years ago... And to this day, it still makes my head hurt.

  • Greg (unregistered)

    "the second parameters is a const reference (not a reference to a const value)"

    I don't think there is such a thing as a non-const reference. Unless you start messing with the underlying raw pointer, a reference will keep referencing whatever it was initialised with... "const someClass &" is exactly the same as "someClass const &", both meaning a reference to a const someClass. Compilers won't allow you to write "someClass & const" (which would be a const reference); probably because there's no non-const reference...

  • TheCPUWizard (unregistered) in reply to Steve_The_Cynic

    "If someone writes a class-specific operator new that returns nullptr on failure instead of throwing std::bad_alloc, you'll get a null back from a failed (by allocation failure) new call for that class."

    I always prefer to return std::random(...) instead... makes for real fun chasing flaming nasal demons...

  • (nodebb) in reply to tom103

    Thankfully, I've never programmed in C++. But I read lots of questions about it on Stack Overflow, and all the recent meta-programming features make my head hurt. It seems like it has become the most bloated language, and the complexity is out of this world.

  • (nodebb)

    as if there's some magical garbage collector which is going to find the unused objects and free them.

    In any decent language, there is.

    Sincerely, Old-aged Lisp Programmer

  • (nodebb)

    "C++ was one of the first "real" languages I learned, more than 25 years ago" C++ was the first language I tried to learn but gave up because it made my head hurt. And mind you, I spent 15 years with Lotus Notes.

  • (nodebb) in reply to Greg

    Compilers won't allow you to write "someClass & const" (which would be a const reference); probably because there's no non-const reference...

    More precisely because the reference variable itself (if there is one(1)) is implicitly, by definition of what references are, const.

    (1) There are some cases where a reference variable exists in concept, but doesn't exist in reality, such as:

    void some_func(void)
    {
        int i = 137;
        int &ref_to_i = i;
    
        // some code that uses ref_to_i as an alias for i
    }
    

    Since every post-definition use of ref_to_i is semantically identical to a use of i and i is right there in the same function, the compiler doesn't actually need to create a true separate variable for ref_to_i, and can just use i directly.

  • LZ79LRU (unregistered)

    All you whippersnappers complaining about C++ just need to toughen up. Back in my day we would have killed for C++. Hell we'd have killed for C. All we had to work with was assembly. And we didn't have any of those fancy compilers either. I had to write my code on a piece of paper and than consult a paper manual to translate each command into its appropriate numerical value before punching it onto a card by hand. And yes, by hand. The punching machine was constantly breaking for some bloody reason and management was too cheap to buy a new one.

  • TheCPUWizard (unregistered) in reply to LZ79LRU
    Comment held for moderation.
  • Álvaro González (github)

    C++ syntax makes Perl look plain English by comparison.

  • Tim (unregistered)
    Comment held for moderation.
  • Duke of New York (unregistered)
    Comment held for moderation.
  • (nodebb)

    I hate the 'const goes first' style of programming. Which is probably why it's the default for all reformatters and you have to go to great lengths to get it in a more sensible place.

  • (nodebb) in reply to Álvaro González

    Perl can actually look downright beautiful if one isn't trying to mimick 1980s C code or go golfing. Like with most languages, it just takes some care and effort, such as giving identifiers useful names rather than one or two character names that can resemble a cross between vintage C and obfuscated JavaScript.

  • ismo (unregistered)

    Depending of the receiving function, it might use & operator and store internally the pointer and free it sometime later. But very dubious code still. I would expect C# developer using C++ and and not understanding the differences of object life times.

  • (nodebb)

    I'm very familiar with this kind of code. Any codebase that evolved from using C-like practices to C++-like practices has this unwieldy melange of pointers and references.

    Now I agree, it is very likely a leak. But as ismo and others say, it theoretically might not be (may the markdown gods smile on me):

    class A {
    public:
        int* i;
        A() { i = new int(42); printf ("create i = %p\n", i); }
        A(const A& a) { i = a.i; }
        ~A() { printf ("destroy i = %p\n", i); }
    };
    
    class B {
    public:
        A *a;
        B(A& _a) { a = &_a; }
        ~B() { delete a; }
    };
    
    int main () {
        B b (*new A);
    }
    

    prints:

    $ g++ a.cxx && ./a.out
    create i = 0x55a3f4ef9ed0
    destroy i = 0x55a3f4ef9ed0
    

    Addendum 2025-03-13 10:07: Oops, a bug. Destructor should be:

    ~A() { delete i; printf ("destroy i = %p\n", i); }
    
  • Duke of New York (unregistered) in reply to thosrtanner

    You can reach the sensible place at once merely by submitting to decades of C and C++ convention.

Leave a comment on “Expressing a Leak”

Log In or post as a guest

Replying to comment #674989:

« Return to Article