Nested Redundant try catch blocks



  • @TheCPUWizard said:

    RAII is quite simple and powerful, but almost always over complicated. If "Resource Allocation IS Initialization" then it means you NEVER have an "uninitialized" object. Period. Simple. If an insance can not be properly initialized to "do what it is supposed to" then the "allocation" itself fails, and you never get to see the instance.
     

     What is your point here? RAII advocates just this - open in constructor, close in destructor. The key thing is having a destructor, so you can close the resource when it goes out of scope instead of relying on the user of your object explicitly closing it when they are done. 



  • @tdb said:

    struct UseResource
    {
      Resource &res;
      UseResource(Resource &r): res(r) { res.bind(); }
      ~UseResource() { res.unbind(); }
    };
    

    void render_something()
    {
    UseResource use_tex(texture);
    UseResource use_shader(shader);
    UseResource use_vbuf(vertex_buffer);

    /* Now do the rendering */
    }

    The drawback is that you need to give names to the RAII objects; unfortunately the language doesn't support anonymous scoped objects.

     

    Just wanted to add that I think this is quite logical and a nice design - consider the example with a db connection URL vs an open connection - (DbConnectionUrl, DbConnection). Or a file - (FilePath, FileReader/Writer). Its nice to know that once you have a DbConnection it is open...

     



  • @Obfuscator said:

    @TheCPUWizard said:

    RAII is quite simple and powerful, but almost always over complicated. If "Resource Allocation IS Initialization" then it means you NEVER have an "uninitialized" object. Period. Simple. If an insance can not be properly initialized to "do what it is supposed to" then the "allocation" itself fails, and you never get to see the instance.
     

     What is your point here? RAII advocates just this - open in constructor, close in destructor. The key thing is having a destructor, so you can close the resource when it goes out of scope instead of relying on the user of your object explicitly closing it when they are done. 

    I believe the point to be that sometimes RAII is misimplemented or implemented in an unnecessarily complex way. I know of at least one library where objects can be created in an uninitialized state and then have create(...) called on them afterwards. This combines RAII and smartpointer semantics in a single class (or rather, a couple dozen of different classes which all behave in the same way).

    Unfortunately there are cases where especially the teardown part of RAII has to be violated. Examples include network sockets, or pretty much any form of IPC. Since the other endpoint may go away unexpectedly, operations on the local object may start failing while the object is still alive. It can't be deleted though, since someone may still have a pointer to it (or worse, it could be on stack, or a direct member of a larger object). So the best bet is to set some kind of [i]invalid[/i] flag and let the user know through whatever error handling mechanism is present. (It can be argued that this does not violate RAII since the OS-level socket object still exists.)



  • @tdb said:

    I believe the point to be that sometimes RAII is misimplemented or implemented in an unnecessarily complex way. I know of at least one library where objects can be created in an uninitialized state and then have create(...) called on them afterwards. This combines RAII and smartpointer semantics in a single class (or rather, a couple dozen of different classes which all behave in the same way).

    Unfortunately there are cases where especially the teardown part of RAII has to be violated. Examples include network sockets, or pretty much any form of IPC. Since the other endpoint may go away unexpectedly, operations on the local object may start failing while the object is still alive. It can't be deleted though, since someone may still have a pointer to it (or worse, it could be on stack, or a direct member of a larger object). So the best bet is to set some kind of invalid flag and let the user know through whatever error handling mechanism is present. (It can be argued that this does not violate RAII since the OS-level socket object still exists.)

    Sure you can misinterpret and/or implement RAII wrong, and it is not the answer to everything. But its a very useful technique! I believe that the examples you bring up can at least partially be solved with a combination of exceptions and substate representations. But standard c-style return values can also be good in certain situations, in my experience especially when you dont want to optimize for the 'happy path' (i.e no errors, all well). But RAII fits a lot of simple usecases really well and makes one able to keep the client API clean by embed the cleanup code in the class itself, something I personally find very important in OO.


Log in to reply