The abhorrent šŸ”„ rites of C



  • @asdf said:

    Those classes are in the standard library.

    Where is the standard library class to call Enable() on a class that the standard library knows nothing about, in a hierarchy that the standard library knows nothing about? This is going from "wrong" territory to "outright lie" territory very quickly.


  • Winner of the 2016 Presidential Election

    This is going to be a C++17 feature, as I said. Any other questions?

    (Boost has something like that already and you can also usually just copy&paste the code from the standards proposal.)



  • @asdf said:

    This is going to be a C++17 feature, as I said. Any other questions?

    No, what's going to be a C++17 feature is something whose use in code is slightly more complicated than an explicit try/finally, and whose implementation is significantly worse. (And it requires 18 pages to describe it, apparently. try/finally can be described, perfectly comprehensibly, in a paragraph or two.)


  • Discourse touched me in a no-no place

    @NeighborhoodButcher said:

    Yeah, because you remember you can't do it on a FILE.

    Stop trying to use stdio as an example of good code. You're just embarrassing yourself. The only good thing about it are sprintf and sscanf, and those two functions are very sharp tools (i.e., excellent in the hands of people who know how to use them, and hazardous in the hands of ignorant idiots).


  • Winner of the 2016 Presidential Election

    @Mason_Wheeler said:

    try/finally can be described, perfectly comprehensibly, in a paragraph or two

    Description plus all the standardese plus a sample implementation in two paragraphs? :rofl:

    Also, that 18-page document describes more than just scope_exit().


  • area_pol

    @Mason_Wheeler said:

    Yeah. You need ugly hacks like RAII in C++ because the language is broken and it doesn't have a proper try/finally construct. Which is interesting because RAII, in its entirety, is built upon a try/finally construct, but it's not exposed to the C++ developer, which means that other uses of try/finally that don't involve freeing memory turn into ugly workarounds. It's the very definition of "abstraction inversion."

    finally is not needed in C++ is what you'd probably heard already. Well, it's true, but it does leave a hole when something, like your example, is needed. That's where helper like boost scope exit come into place. C++ could have both, I guess.

    But the point about RAII is off. It's more logical that an object which owns resources should be responsible for releasing them. try/finally way is moving that responsibility to the owner of the owning object. It was designed because you don't have destructors in languages which use that construct and that's all. And you can't have destructors when your object lifetime is not clearly defined, but depends on whatever GC feel right now.


  • Winner of the 2016 Presidential Election

    @Mason_Wheeler said:

    And it requires 18 pages to describe it

    BTW: A simple implementation is just a few lines long:


  • Discourse touched me in a no-no place

    @asdf said:

    Description plus all the standardese plus a sample implementation in two paragraphs?

    It takes a bit more than that. [spoiler](I can't be bothered to look up the equivalent for C#; it'll be a bit shorter because it uses a different keyword for some of the semantics. The overall length of the two will probably be not hugely different; the semantics of the two languages are quite comparable at this level, despite what some fanbois claim.)[/spoiler]


  • Winner of the 2016 Presidential Election

    Exactly. He's comparing apples (simple description) and oranges (language standard proposal).


  • area_pol

    @PJH said:

    Now - do I need to use delete or delete[] on this pointer...?

    When you have non-owning raw pointer, which should be the norm as opposed to C, you never call delete. Your problem is solved by not creating it in the first place.



  • @NeighborhoodButcher said:

    But the point about RAII is off. It's more logical that an object which owns resources should be responsible for releasing them. try/finally way is moving that responsibility to the owner of the owning object.

    Wait, what?

    @NeighborhoodButcher said:

    It was designed because you don't have destructors in languages which use that construct and that's all.

    Huh?

    @NeighborhoodButcher said:

    And you can't have destructors when your object lifetime is not clearly defined, but depends on whatever GC feel right now.

    Umm... where in the world did you get the idea that try/finally is exclusively a managed code thing? (And again, try/finally is not about destructors, memory management, or resource management. Get that idea out of your head. It's completely wrong, and as long as you keep thinking about it that way you'll never understand it. That's only one of many things it can be used for.)



  • @asdf said:

    Please name 5 use cases for finally that do not involve resource management and are made unnecessarily complicated by the fact that C++ favors RAII.

    I don't use C++ a lot, but one example comes readily to mind:

    • You can't use RAII when you need a variable of an abstract/partial class.

    You'll run into this any time you need to determine which class is the correct implementation of an abstract class at runtime.


  • Winner of the 2016 Presidential Election

    @powerlord said:

    You can't use RAII when you need a variable of an abstract/partial class.

    I'm not sure I follow. Care to elaborate?


  • Discourse touched me in a no-no place

    @Mason_Wheeler said:

    Umm... where in the world did you get the idea that try/finally is exclusively a managed code thing?

    Technically, it's a semantics thing: the finally clause executes when the body of the try terminates (and after any catch clauses have been processed) whether the overall result of the evaluation is success, a break/continue signalling (a different sort of success), a return (yet another kind of success) or an exception. If the finally clause does not throw an exception, the result of the overall construct is the same as if the finally clause was not there. It's strongly recommended that finally clauses be kept simple (so no throw, break, continue or return) because while not keeping them simple is well-defined, the resulting program is rather difficult to debug. šŸ˜„

    And it looks like I have :disco:spaces in my post. Thanks, @end! :doing_it_wrong:


  • area_pol

    @PJH said:

    With all these perfect solutions to avoid the problems, would someone like to tell me why malloc(), new and new[] are still things in C+11, since they got rid of other things (like the old meaning of auto)? šŸ¹

    Any answers that involve keeping them there will be directed back to my original question.

    Why do you claim they're still a thing? Today nobody uses new except in-place construction. Nobody uses delete, because you have smart pointer for this. malloc() or equivalent is only used deep down in allocators, which probably 99% of programmers will never touch.


  • area_pol

    @Mason_Wheeler said:

    That makes even less sense. Why in the world would you destroy your mutex while it's still in use?

    You're right, that's why it's considered an error and undefined behavior.



  • @NeighborhoodButcher said:

    You're right, that's why it's considered an error and undefined behavior.

    Yeah, sorry about that. Terminology confusion. Someone said "owner" in a conversation about resource disposal, and I thought they meant "owner" in the memory management/resource disposal sense, when they really meant "lock holder."


  • area_pol

    @Mason_Wheeler said:

    It's still stupid to create an entire class to do what you should be able to do in one line of code without having to create a class for it. (And even stupider to create a template to create that class!)

    std::unique_lock lock{mutex}; // one line
    

    As for the template - there many kinds of mutexes, you know (or not). You can even write your own thing, which is lockable and use a unique_lock on it. Note it isn't named unique_mutex_lock.



  • One line that instantiates an object from a class that had to be created because the language is so broken that it's incapable of doing this without a class!



  • @Mason_Wheeler said:

    You need ugly hacks like RAII in C++ because the language is broken and it doesn't have a proper try/finally construct.

    @dkf said:

    One of the better code-structure inventions of recent years has been the using/try-with-resources of C# and Java.

    The problem with that is they're not transitive, while RAII is (i.e. destruction of an object will always trigger a destruction of all of its members). And it removes the need for designing a disposed state for a type. Which can significantly reduce mistakes ("someone added a disposable thing to this disposable thing but forgot to update Dispose" etc). You can get around that (IoC or generating code or whatever) but RAII gives you that for free, and for all types.

    You might not see anything wrong with manually maintained disposing code (it's certainly doesn't bother me most of the time due to not writing anything state-heavy), but calling RAII a hack is dumb. It's automation of correctness.

    @Mason_Wheeler said:

    try/finally is not about resource management.

    For vast majority of cases it is. For others it's just syntactic sugar.

    @Mason_Wheeler said:

    Then why are memory leaks so common in released software written in C++? Must not be as magically simple as you claim.

    Because people think like you and not use RAII.

    @dkf said:

    The only good thing about it are sprintf and sscanf

    Haha, no.


  • area_pol

    @Mason_Wheeler said:

    Oh, right! C++'s object model is utterly broken. It has objects-as-value-types, which should never exist in the first place. But that's a completely different discussion.

    Goddamn, that's even a more absurd statement than what that C guy writes.



  • @asdf said:

    @powerlord said:
    You can't use RAII when you need a variable of an abstract/partial class.

    I'm not sure I follow. Care to elaborate?

    Say I have a class named BuiltinVoteStyle_Base that has 9 methods defined in its header file, but only implements 4 of those methods in its .cpp file. The other 5 are declared as virtual.

    I then have 3 classes that extend that class that each implement the 5 missing methods.

    You can't declare

    BuiltinVoteStyle_Base voteStyle;
    

    because that's a compiler error. You must declare it as some sort of pointer and set it to an instance of the correct class at runtime.

    I've actually run into this writing an addon for Valve game servers, with different implementations for Left 4 Dead, Left 4 Dead 2, Team Fortress 2, and Counter-Strike: Global Offensive1.

    1I didn't actually do the CS:GO one before I realized certain operations were just easier to do from the SourceMod scripting host instead of directly through C++

    Filed under: I could have just said "Polymorpism", This particular code had to compile using the Visual Studio 2008 compiler and GCC 3.x so no std::unique_ptr


  • Winner of the 2016 Presidential Election

    @Mason_Wheeler said:

    One line that instantiates an object from a class that had to be created because the language is so broken that it's incapable of doing this without a class!

    If, at this point, you still don't get the benefits of using an explicit object for the resource, after all the examples and explanations, then there's no point in arguing with you:

    @asdf said:

    I was also talking about this case:

    std::unique_lock<std::mutex> foo() {
    // lock some mutex
    return lock;
    }

    std::unique_lock<std::mutex> bar() {
    // do stuff
    return foo();
    }

    int main() {
    auto lock = bar();
    // do stuff
    return 0;
    }

    Really easy to handle with RAII, extremely unintuitive and error-prone if you don't have an object that represents the lock you're holding.


  • ā™æ (Parody)

    @Mason_Wheeler said:

    One line that instantiates an object from a class that had to be created because the language is so broken that it's incapable of doing this without a class!

    I thought one of the philosophies of C++ was to be able to implement as code stuff that other languages had to write into the language. I'm sure we could all fight over the desirability of that.


  • area_pol

    @Mason_Wheeler said:

    Then why are memory leaks so common in released software written in C++? Must not be as magically simple as you claim.

    Because not everybody uses smart pointer, while they should. Also dealing with C API can add the burden (but that's another fire I wish to start when this one is done).

    @Mason_Wheeler said:

    Memory leaks are common in C++ software. Memory leaks are common in software written in other native languages, where memory must be managed manually.

    And here you strike gold. Just don't do it. Don't be stupid. Don't write C-like code in C++.



  • @NeighborhoodButcher said:

    And how many times can you NOT search why/where C++ outperforms C?

    Uhm dude, I'm on your side of the argument here (long-time C programmer, switched to C++/C#, wincing whenever I use C again), but the burden of proof is on you. Someone debating against you isn't going to bother searching for evidence in your favor. Hell, even I won't. That's your job to do the googling, and link (or even better, quote and link) the results.

    Such is the nature of asinine Internet forum debates. And probably meatspace debates, as well.


  • Winner of the 2016 Presidential Election

    @powerlord said:

    You must declare it as some sort of pointer and set it to an instance of the correct class at runtime.

    Ok, but how does that relate to RAII? std::unique_ptr<Derived> is move-assignable to std::unique_ptr<Base>.


  • area_pol

    @dkf said:

    Stop trying to use stdio as an example of good code. You're just embarrassing yourself.

    Whoa, where did you get that idea? stdio good code? How? When?



  • @powerlord said:

    You can't use RAII when you need a variable of an abstract/partial class.

    @powerlord said:
    Say I have a class named BuiltinVoteStyle_Base that has 9 methods defined in its header file, but only implements 4 of those methods in its .cpp file. The other 5 are declared as virtual.

    I then have 3 classes that extend that class that each implement the 5 missing methods.

    You can't declare

    BuiltinVoteStyle_Base voteStyle;
    

    because that's a compiler error. You must declare it as some sort of pointer and set it to an instance of the correct class at runtime.

    But you can use an unique_ptr<BuiltinVoteStyle_Base>.


  • area_pol

    @Mason_Wheeler said:

    Wait, what?

    What what?

    You either have an object which owns a resource (let's say a stream) and that objects releases that resource when it gets destroyed, or you have that object again, but YOU have to remember to explicitly call some close() function for the object to release it's underlying resources. That's a pretty simple example, IMHO.

    @Mason_Wheeler said:

    Huh?

    Care to write full sentences?

    @Mason_Wheeler said:

    Umm... where in the world did you get the idea that try/finally is exclusively a managed code thing?

    Which languages invented them?


  • area_pol

    @Mason_Wheeler said:

    Yeah, sorry about that. Terminology confusion. Someone said "owner" in a conversation about resource disposal, and I thought they meant "owner" in the memory management/resource disposal sense, when they really meant "lock holder."

    Technically it's called a lock owner, not a holder, hence the misunderstanding.


  • area_pol

    @Mason_Wheeler said:

    One line that instantiates an object from a class that had to be created because the language is so broken that it's incapable of doing this without a class!

    That's a pretty moot argument. I can also say the opposite: try/finally was created because the language is so broken that it cannot have deterministic destructors.



  • @Kian said:

    To get the same kind of optimization opportunities, the C programmer would have to write a specialized sorting function for each type, repeating the same code over and over with just a change in the comparator called.

    Bullshit.

    Template instantiation creates specialised code at compile time, which is great, but it's not an optimisation in itself, nor does it allow for additional specialisation.

    A C coder might well do much the same thing (without the type safety benefits) using a macro, or simply by using aggressive inlining (which specialises code at the call site, keeping all the type safety benefits).

    There is nothing in this example, optimisation-wise, which C++ can do that can't also be done in C, given a good enough compiler. C++ does provide a lot of optimisation hints to the compiler that C doesn't, but on the other hand it's so hideously fucking complex compared to C it's much easier to write horribly inefficient code using it.

    All of which is not to say that C is a wonderful language. It's not. It's a fucking horrible blot on the world of IT, arguably far more damaging than even PHP. It's just that C++ is more of it. Complication piled on complication piled on Rube Goldberg device, but it still somehow needs Boost to make it usable. It doesn't help that nobody knows what version of C++ you're talking about when you say "C++", either. See the hundreds of posts over the last day...


  • area_pol

    @Medinoc said:

    Uhm dude, I'm on your side of the argument here (long-time C programmer, switched to C++/C#, wincing whenever I use C again), but the burden of proof is on you.

    The fact is I did a quick google and linked a page in a book (and you guys seem to have DoSed Google Books šŸ˜„ , which explains one of the mechanisms why this is true. On the other hand he either completely ignored it, or didn't understand any of it.



  • @CatPlusPlus said:

    You might not see anything wrong with manually maintained disposing code (it's certainly doesn't bother me most of the time due to not writing anything state-heavy), but calling it a hack is dumb. It's automation of correctness.

    I have nothing against "the automation of correctness," assuming what's being automated is actually correct. (Which should not be taken for granted!) What I have a problem with is the abstraction inversion.

    @CatPlusPlus said:

    try/finally is not about resource management.

    For vast majority of cases it is. For others it's just syntactic sugar.

    It's not syntactic sugar, it's a fundamental code flow primitive that becomes necessary as soon as you introduce exception handling to the language, which is why every language that supports exception handling supports it. (Except C++. See above, re: broken.)

    @NeighborhoodButcher said:

    Goddamn, that's even a more absurd statement than what that C guy writes.

    Got anything to back that assertion up with?

    The sine qua non of objects--what makes them something actually different and useful, something more than simply structs with methods welded on--is polymorphism: inheritance and virtual methods.

    The thing is, you can have inheritance, or you can have value types. You can't have both, or you run into all sorts of huge messes when you try to assign or pass objects. (Copy constructors, object slicing, etc.) Value-type semantics utterly ruin inheritance and all the benefits it brings to the table.

    @asdf said:

    If, at this point, you still don't get the benefits of using an explicit object for the resource, after all the examples and explanations, then there's no point in arguing with you:

    1. You have not explained any benefits. You have shown examples that are more complicated than explicit try/finally, and asserted that a benefit exists, but at no point has this benefit been demonstrated, because it does not exist.
    2. There's that word again, "resource." You're still thinking of it in terms of resource management. Are you literally incapable of getting out of that wrong mental model?

    @NeighborhoodButcher said:

    What what?

    You either have an object which owns a resource (let's say a stream) and that objects releases that resource when it gets destroyed, or you have that object again, but YOU have to remember to explicitly call some close() function for the object to release it's underlying resources. That's a pretty simple example, IMHO.


    Sure, but how does that have anything to do with "moving that responsibility [from the owning object] to the owner of the owning object"?

    @NeighborhoodButcher said:

    Care to write full sentences?

    Care to write stuff that actually makes sense?

    @NeighborhoodButcher said:

    Which languages invented them?

    Not sure where it originally came from In The Beginning, but I do know that Pascal had it (and destructors) before Java or C# even existed. This is because try/finally is not about object destruction; it's about exception safety.

    @NeighborhoodButcher said:

    That's a pretty moot argument. I can also say the opposite: try/finally was created because the language is so broken that it cannot have deterministic destructors.

    You can say that, but you would be objectively wrong to say so, because it existed before the concept of managed code and "no deterministic destructors" was invented.


  • area_pol

    @tufty said:

    Template instantiation creates specialised code at compile time, which is great, but it's not an optimisation in itself, nor does it allow for additional specialisation.

    And that is entirely not true, because the compiler can optimized different specializations differently. Templates are not C macros where you simply get a blob of text pasted into.



  • @NeighborhoodButcher said:

    @tufty said:
    Template instantiation creates specialised code at compile time, which is great, but it's not an optimisation in itself, nor does it allow for additional specialisation.

    And that is entirely not true, because the compiler can optimized different specializations differently. Templates are not C macros where you simply get a blob of text pasted into.


    Of course the compiler can optimise different specialisations differently. It can also optimise different "blobs of pasted text" differently. In both cases you're talking about different pieces of code, which can thus can be optimised differently.



  • Okay, concrete example time. I code in C#. C# is a language that has both a destructors mechanic and a try/finally mechanic (and yes, the former is merely syntactic sugar for the latter).

    And you know what? Try/finally is cumbersome. If there's anything I need to do (and undo with finally) several times, I'm going to use an IDisposable-implementing object in a using block.

    I have a class for changing the foreground color of the console output and changing it back when disposed. I have a class for swapping any two values and swapping them back when disposed. I even have a class to call a parameterless delegate (=function pointer, for those who don't know .net) (or even a lambda expression) when disposed. All this because a using block is less cumbersome than try/finally.

    That's just how cumbersome try/finally is, compared to RAII mechanics.


  • area_pol

    @Mason_Wheeler said:

    Got anything to back that assertion up with?

    Two words - moving ownership. Follow it up.

    @Mason_Wheeler said:

    The thing is, you can have inheritance, or you can have value types. You can't have both, or you run into all sorts of huge messes when you try to assign or pass objects

    That's called slicing in C++ and it's a thing only stupid programmers do. Compilers tend to scream at this, tho.

    @Mason_Wheeler said:

    Sure, but how does that have anything to do with "moving that responsibility [from the owning object] to the owner of the owning object"?

    Read that long sentence again and see who initiated resource release.

    @Mason_Wheeler said:

    Care to write stuff that actually makes sense?

    Pretty hard when all I get from you is "huh".

    @Mason_Wheeler said:

    This is because try/finally is not about object destruction; it's about exception safety.

    Wrong - it's about resource release/cleanup, which needs to be executed always. Much like deterministic destruction of objects.

    @Mason_Wheeler said:

    You can say that, but you would be objectively wrong to say so, because it existed before the concept of managed code and "no deterministic destructors" was invented.

    Care to elaborate on that, because I have a feeling you didn't exactly get my point?


  • area_pol

    @tufty said:

    Of course the compiler can optimise different specialisations differently. It can also optimise different "blobs of pasted text" differently. In both cases you're talking about different pieces of code, which can thus can be optimised differently.

    The example from that book shows how templates can be more optimized than macros, if you wish. Templated functor can be inlined, while no macro will save you from indirect C-style function call.



  • @Mason_Wheeler said:

    the language is so broken that it's incapable of doing this without a class!

    Why do you hate classes? Writing classes is the main way you create abstractions in C++. They're used to codify concepts and relationships. When you have a new concept you want to handle, you write a class for it. It's not a failure of the language, is how it's intended to be used.

    @powerlord said:

    You must declare it as some sort of pointer and set it to an instance of the correct class at runtime.
    Well, yeah. What would you want to happen if you instantiate the base class and call one of the undefined virtual methods? The compiler keeping you from making mistakes is a GOOD thing, not an error.

    @Mason_Wheeler said:

    The sine qua non of objects--what makes them something actually different and useful, something more than simply structs with methods welded on--is polymorphism: inheritance and virtual methods.
    [Citation needed] Just because one language calls something one way, doesn't mean every language has to be limited that way. I get a lot of mileage out of classes without ever writing a single virtual method.

    @Mason_Wheeler said:

    The thing is, you can have inheritance, or you can have value types. You can't have both, or you run into all sorts of huge messes when you try to assign or pass objects. (Copy constructors, object slicing, etc.) Value-type semantics utterly ruin inheritance and all the benefits it brings to the table.
    According to @Ronin, OOP sucks and C++ sucks because it has too much of it. You complain that C++ isn't committed enough to OOP. Neither of you have a clue about C++.



  • @NeighborhoodButcher said:

    Templated functor can be inlined, while no macro will save you from indirect C-style function call.

    A indirect function call can be inlined at its call site as well, as long as it can be proven the function being called will always be the same. In the case we're talking about, the equivalent of a C++ templated algorithm, the indirect function call will always be the same, and can almost certainly be reduced to a direct call, or even an inlining of the function. C optimisation does not stop at "expand templates".


  • area_pol

    @tufty said:

    A indirect function call can be inlined at its call site as well, as long as it can be proven the function being called will always be the same.

    Unfortunately, the compiler cannot check this, but that would be a nice optimization.



  • @tufty said:

    Complication piled on complication piled on Rube Goldberg device, but it still somehow needs Boost to make it usable.

    Eh, not so much these days. But yes, C++ is a terrible language with a shitty ecosystem and using it is a pain. RAII as a concept is not C++-specific, though (Rust has Drop trait for that, for example), and holding RAII against C++ is literally insane and a sign of :doing_it_wrong:

    @Mason_Wheeler said:

    It's not syntactic sugar, it's a fundamental code flow primitive that becomes necessary as soon as you introduce exception handling to the language, which is why every language that supports exception handling supports it.

    99% of need for always executing given code even when unwinding is external resources. I rarely ever write finally in any language (and I've never felt the need to in C++), especially if it has using-like blocks. Because unlike what you think, writing helper types for that is not a problem, and it makes maintenance of call sites less error-prone.



  • @NeighborhoodButcher said:

    Two words - moving ownership. Follow it up.

    So... more context-less gibberish from you. Gotcha

    @NeighborhoodButcher said:

    Wrong - it's about resource release/cleanup, which needs to be executed always.

    it's about arbitrary cleanup which needs to be executed always, and the reason it exists is because it's necessary for correct cleanup when exceptions can be thrown. It has as much to do with object destruction as glass jars have to do with fruit jam: that's one thing that is frequently found inside of them.

    @NeighborhoodButcher said:

    Care to elaborate on that, because I have a feeling you didn't exactly get my point?

    What is there to elaborate on? Pascal had try/finally before Java and C# made OOP with non-deterministic object cleanup a thing. Therefore, it's objectively incorrect to claim that it's something that was created to address a lack of deterministic object cleanup. If that's not the point you're attempting to make, please state your point more clearly, because that's what you said.

    @Kian said:

    Why do you hate classes?

    Why do people keep asking stupid questions that I already answered even though they were stupid the first time? I don't hate classes; I hate using the wrong tool for the job, particularly when they're more complicated than using the right tool for the job.

    @Kian said:

    Writing classes is the main way you create abstractions in C++.

    So what you're saying is, when all you have is a šŸ”Ø, everything starts to look like a class?

    @CatPlusPlus said:

    99% of need for always executing given code even when unwinding is external resources.

    You don't do much GUI work, do you?

    @CatPlusPlus said:

    Because unlike what you think, writing helper types for that is not a problem, and it makes maintenance of call sites less error-prone.

    ...and you don't do much maintenance work, do you? Because if there ever was an inviolable First Law of Maintenance Thermodynamics, it would be this: the more layers of abstraction your implementation is buried under, the harder it is to debug and fix because the harder it is to find out what is actually going on and where it's taking place.



  • @Mason_Wheeler said:

    You don't do much GUI work, do you?

    Feel free to present examples of how fundamental finally is in GUI code.


  • Winner of the 2016 Presidential Election

    @tufty said:

    it still somehow needs Boost to make it usable

    That hasn't been true for years.

    @Mason_Wheeler said:

    You have not explained any benefits

    I even showed you example code in the very post you replied to. I'm starting to get the feeling that you are actively ignoring my points.

    @Mason_Wheeler said:

    There's that word again, "resource."

    Yes, because my example, whose existence you deny, uses RAII for resource management.

    @Mason_Wheeler said:

    Are you literally incapable of getting out of that wrong mental model?

    Maybe I disagree and think it's the correct mental model in most cases. But I also linked to the standards proposal which provides a generic RAII wrapper for non-resources.

    Yes, you're actively ignoring my points.

    @Mason_Wheeler said:

    This is because try/finally is not about object destruction; it's about exception safety.

    Those two things are not as unrelated as you make it seem.

    @CatPlusPlus said:

    RAII as a concept is not C++-specific, though (Rust has Drop trait for that, for example), and holding RAII against C++ is literally insane and a sign of :doing_it_wrong:

    QFFT


  • Winner of the 2016 Presidential Election

    @Mason_Wheeler said:

    You don't do much GUI work, do you?

    Occasionally, and I use QML for the GUI. Your point being?


  • area_pol

    @Mason_Wheeler said:

    So... more context-less gibberish from you. Gotcha

    No, just something you actually can look up. Or you can just play dumb and evade it, since it would prove you wrong.

    @Mason_Wheeler said:

    it's about arbitrary cleanup which needs to be executed always, and the reason it exists is because it's necessary for correct cleanup when exceptions can be thrown. It has as much to do with object destruction as glass jars have to do with fruit jam: that's one thing that is frequently found inside of them.

    So you're disputing my claim of it being used for cleanup by saying that it's being used for cleanup?

    @Mason_Wheeler said:

    What is there to elaborate on? Pascal had try/finally before Java and C# made OOP with non-deterministic object cleanup a thing. Therefore, it's objectively incorrect to claim that it's something that was created to address a lack of deterministic object cleanup. If that's not the point you're attempting to make, please state your point more clearly, because that's what you said.

    My point was that you've made a statement which only bases on your assumptions. I showed you how absurd it looks, by making the inverted one.



  • @NeighborhoodButcher said:

    @tufty said:
    A indirect function call can be inlined at its call site as well, as long as it can be proven the function being called will always be the same.

    Unfortunately, the compiler cannot check this, but that would be a nice optimization.


    Again, bullshit. In the case you're talking about, std::sort, you provide a fixed functor, right? So to compare apples with apples, you'd have to allow me something like
    [code]
    #define std_sort(begin, end, functor) \
    ā€¦
    [/code]
    So when I then use it, thusly
    [code]
    std_sort (foo, bar, &compare);
    [/code]
    the expansion at that point will have a known value, and can be inlined. A far less common usage might be
    [code]
    int_t (*compare_p)(int, int) = &compare;
    ā€¦
    std_sort (foo, bar, compare_p);
    [/code]
    But again, at the call site, compare_p has a known, static, value, and can probably be inlined. And so on, including passing in various function pointers, which can be dealt with by rolling the sort algorithm "up" the call stack and specialising for the various types, ā€¦

    Obviously, this requires a smart enough compiler, and one of those probably doesn't exist for C (or, in most cases, for C++). But the idea that those optimisations cannot be made for C is false.


Log in to reply