Thread: Some questions on noexcept, constexpr, namespaces, etc.

  1. #1
    Registered User
    Join Date
    Aug 2019
    Location
    inside a singularity
    Posts
    300

    Some questions on noexcept, constexpr, namespaces, etc.

    Trying to learn noexcept, constexpr, etc. in C++ which I've neglected learning for so long. It wasn't taught at school either (well, neither was most of actual C++ except cin and cout and the rest being C primarily, but I didn't know the difference back then when I considered Turbo C/C++ OP). So, I'm learning through practice and cppreference examples. I know a little about them as I've read about many of these keywords in the past but I've never practiced using them until now.

    My questions (some of them, I believe I know the answer to, but there's no harm in making sure if I'm right and some of them that are probably stupid):

    (1) If I have a base class containing implementations and another class that inherits from it providing an interface, do I qualify the ctors of the interface class and utility functions as noexcept (because they don't actually throw any exceptions, in the case where base class does all the exception handling) or do I handle any exception raised and rethrow it for the end use to manage it?

    (2) If a class contains an object of another class (let's say vector), and it happens to throw an exception due to the end users mistake (but my code is what is processing the end user's request to do anything), do I have to handle the exception and rethrow it or can I just let it be?

    (3) When is it really important to specify noexcept? Even for non-throwing functions(/...etc), not qualifying them with noexcept will make them potentially throwing functions(/...etc) but that wouldn't matter if they don't raise any exceptions at all.

    (4) Is noexcept simply syntax sugar sort of thing? Well, it does guarantee the called function(/...etc) will not throw any exceptions but I don't think it hurts even if there's a non-throwing function unqualified with noexcept. What's exactly will it help in?

    (5) If there's a templated implementation of some sort that has 'T' as type and in the implementation, if there exist code like "if (typeid(T) equals typeid(double))" for different primitive types, will it be considered bad practice. I think yes because this can simply be done in a different and more obvious and intuitive way.

    (6) If a class implementation does not want to have objects being created at runtime, only then should its ctors be qualified with constexpr?

    (7) Does using a "using namespace" directive inside another namespace affect the end user? If I had a "using namespace std;" somewhere inside another namespace "namespace X" and the user does something like "using namespace X;", std does not end up getting used too, right? I tried some code and this holds true. Although, is it good practice to have using directives inside namespaces? I think yes, why not? Simplifies a lot of code and makes it readable as long as there's no naming clashes between multiple to-be-used namespaces.

    (8) Can I, in general, specify a function that performs some utility action as constexpr? I think not, but I don't know why.

    (9) When will C++20 become a thing? I've read about many new concepts being introduced, making it something Java-like with things like "requires Comparable <T>", etc. I've read that it's great and would like to stay updated on the new developments so that I don't struggle like I'm struggling now.

    (10) constexpr replaces every usage of macros (not just compile time constants but even "function" like macros) completely? I think yes, and would like any counter-example if possible.

    (11) If Q10 is true, will we be seeing the entire STL being re-written with constexpr statements instead of the define configurations?

    (12) When is it good to specify a dtor as noexcept?

    (13) If I have a class which contains an object of another class whose dtor is not noexcept, but my class doesn't really throw any exceptions, should I be the one handling that exceptions and rethrowing it to the user. I believe this is similar to another question asked above.

    (14) Is it good style for an implementation class to contain all sorts of utility functions and then have an interface class access them as needed, or, is it better to let the interface class handle utility functions? Let's say I have in my implementation class a index [] operator overload and I also want to provide an at () function that does exactly the same as [], do I implement at () as an implementation class feature and let the interface class access it or do I simply write utility code only for the interface class? I think the latter is better because the implementation class should consist strictly only the necessary implementations. Is it just a matter of style?

    I apologise if some questions are stupid or if I haven't conveyed what I wanted to clearly in some questions or if my english went haywire somewhere.

    Thank you very very much
    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." - Rick Cook, The Wizardry Compiled

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,748
    For 1, 3, 4, and 12: C++ Core Guidelines: E.12: Use noexcept when exiting a function because of a throw is impossible or unacceptable. Note that "we give the compiler and human readers information that can make it easier for them to understand and manipulate" means that this is a form of code-as-documentation that allows for compiler optimisations, e.g., not having to worry about call stack unwinding.

    For 2: it depends on the situation, i.e., you have to decide if it makes sense to translate or propagate the exception.

    For 5: yes, use template specialisation instead

    For 6: that sounds like a wrong motivation for using constexpr. Perhaps the class should be an abstract base class?

    For 7: as I recall, this is poor practice, but the details elude me right now, and I'm curious as to what you tried. Maybe it would have been better to break this up into a bunch of posts with more elaboration rather than try and cram it all into one post.

    For 8, I have no idea as the notion has never crossed my mind as it would likely break the principle of functions having a single purpose, but surely it is trivial to write a test program to check for yourself.

    For 9: by definition, this year. Of course, it's always possible to end up with another C++0x fiasco, but then by definition it won't be C++20.

    For 10: no, I expect that there's still the black magic preprocessor token pasting and stringifying stuff that constexpr cannot handle, along with special macros like __LINE__. Oh, and header inclusion guards, but that may eventually be obsolete depending on how modules work out.

    For 11: other than header inclusion guards, what in the STL uses #define in the first place?

    For 13, note that destructors should not fail, i.e., they should not be throwing exceptions in the first place.

    For 14, a class should only have the minimum number of member and friend functions needed to provide its core functionality or for reasons such as efficiency. Other functionality should be provided by non-member non-friend functions that are implemented in terms of this core interface.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,748
    Quote Originally Posted by Zeus_
    If I had a "using namespace std;" somewhere inside another namespace "namespace X" and the user does something like "using namespace X;", std does not end up getting used too, right? I tried some code and this holds true.
    Consider:
    Code:
    #include <vector>
    #ifndef MINE_H_
    #define MINE_H_
    
    #include <iostream>
    #include <string>
    
    namespace mine
    {
        using namespace std;
    
        inline void print_message(const string& message)
        {
            cout << message << endl;
        }
    }
    
    #endif
    
    int main()
    {
        using namespace mine;
    
        string greeting{"hello"};
        print_message(greeting);
    
        vector<int> numbers{1, 2, 3};
        for (auto&& x : numbers)
        {
            cout << x << endl;
        }
    }
    I have "pasted" a header in so you can imagine a header being included while testing with a single file. So, from the perspective of the reader of the source file containing only the main function, it looks like the std namespace did not have a using directive applied, yet the effect is as if it does, because the using namespace std in the mine namespace brings in those names which are then transitively made available as part of the mine namespace when the using directive for mine is used in the scope of main.
    Last edited by laserlight; 4 Weeks Ago at 04:32 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    Aug 2019
    Location
    inside a singularity
    Posts
    300
    1, 3, 4, 12: The CppCoreGuidelines link is very informative. It's answered many of my questions since yesterday. The funny thing is that I had already downloaded this from the repository but forgot about it, and never ended up reading through. Thank you very much.

    2: That makes sense. If the standard library is throwing some sort of exception like out-of-memory or an out-of-bound access error, it makes sense to let the program crash instead of rethrowing the exception after handling it myself because there's almost really nothing the end user can do anyway.

    5: Yep, makes sense.

    6: Yeah, absolutely right. My bad, this is a stupid question now that I think about it.

    7: My test program is not correctly, again, my bad. Your example is post #3 demonstrates more than enough to clear my doubt. Although, I have one other question. If I have a few nested namespaces like this:

    Code:
    // namespace one acts as the "global" namespace for namespace (like std)
    namespace one {
        namespace two { }
    
        namespace three {
            namespace four {
                using namespace std;
            }
        }
    
        namespace five {
            // I'd like to use namespace four here, let's say. What's the best way to do this?
            using namespace one::three::four; // Like this?
            using namespace three::four; // Also works, right?
    
        }
    }
    
    // If the end user does this:
    using namespace one;
    // std does not end up being brought in completely, right?
    
    // If the end user does this:
    using namespace one::three;
    // std does not end up being brought in completely, right?
    
    // If the end user does this:
    using namespace one::three::four;
    // std does end up being being brought in completely, right?
    
    // If the end user does this:
    using namespace one::five;
    // std does end up being being brought in completely, right?
    
    // This is what I tested after your post and before that I was doing terribly wrong at understanding namespaces (I'm ashamed of it lol)
    
    // If I have quite a few namespaces that I'm working with, what can I do to make code more readable? Example code:
    
    namespace library {
        namespace type {
            typedef int Lint;
        }
    
        namespace support {
            namespace frontends { }
            namespace backends { }
        }
    
        namespace implementation {
            namespace base {
                // I'd like to maybe use namespace std here but I don't want the end user to be impacted
                // by it in anyway. If I use std here, I happen to make the code more readable.
                class foo {
                    std::vector <library::type::Lint> a; // not readable - looks bad
                    std::vector <type::Lint> b; // still slightly bad
                };
                
                // better?
                using namespace std;
                using namespace library::type;
                // implementations to make code readable...
                
                // but like I found out, this is bad code if the user ends up using this namespace...
            }
            namespace interface {
                // if the user is supposed to be using classes from this namespace for using the library,
                // then they end up including the entire std namespace too because of the next line. But,
                // this line helps me keep things readable. What's the best workaround for keeping code
                // readable as well as not screw up with the end user?
                using namespace library::implementation::base;
                class foo_interface {
                    //...
                };
            }
        }
    }
    10: And this is what didn't seem to cross my mind. Nice examples. I'm excited to know about how modules would work, sounds interesting and slightly Pythonic.

    11: All configuration management like in c++config.h? And all the other configuration headers that might be existing that I do now know of.

    13: Right, noted.

    14: Cleared! Keep crap as less as you can with implementation/base classes and provide an interface to the end user using this minimal workable implementation class as long as everything is efficient.

    Thank you laserlight! Great resource for C++ Programming
    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." - Rick Cook, The Wizardry Compiled

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,748
    Quote Originally Posted by Zeus_
    I'd like to use namespace four here, let's say. What's the best way to do this?
    Use a namespace alias:
    Code:
    namespace five
    {
        namespace four = one::three::four;
        // ...
        void foo(const four::some_type& x);
    }
    Granted, this means that instead of one::three::four, someone could use five::four instead, but if you intend to keep this namespace alias as part of the interface, that's fine, otherwise document it as implementation detail and maybe use an underscore name suffix to reinforce the point.

    Quote Originally Posted by Zeus_
    // I'd like to maybe use namespace std here but I don't want the end user to be impacted
    // by it in anyway. If I use std here, I happen to make the code more readable.
    Code:
    class foo {
        std::vector <library::type::Lint> a; // not readable - looks bad
        std::vector <type::Lint> b; // still slightly bad
    };
    Presently, you should qualify names for declarations at namespace scope in a header file. It can become "stutter" when you have to keep doing the same qualification for a single declaration, but it isn't that painful for a short namespace name like std, and with namespace aliases you can turn long names (or nested names) into short ones. The benefit of bearing with the pain of course is that you ensure that you avoid name collision, and this is true even when you can freely use using directives, as in a source file.

    Quote Originally Posted by Zeus_
    10: And this is what didn't seem to cross my mind. Nice examples. I'm excited to know about how modules would work, sounds interesting and slightly Pythonic.
    C++ already has namespaces, whereas Python's modules function as namespaces, so C++ modules are expected to be orthogonal to namespaces, i.e., they are expected to be more specifically a better alternative to headers. I believe that this will alleviate the issue of having to keep using directives out of namespace scope in header files; after all, if there are no more header files, then this problem disappears: you can place a using directive at namespace scope and export the names in the namespace rather than exporting the entire namespace, in which case only those names will be imported when the module is imported, not the names from the namespace of the using directive at namespace scope.

    Quote Originally Posted by Zeus_
    11: All configuration management like in c++config.h? And all the other configuration headers that might be existing that I do now know of.
    I did a quick check of the standard library headers, both the main C++ headers and the additional headers inherited from C, and from what I see neither <c++config> nor <c++config.h> is listed among them, so this header is not part of the standard library, and therefore not from the parts of the standard library that we might call the "STL".

    A quick search of the Web brings up bits/c++config.h from the GNU ISO C++ Library, but the file's own documentation clearly states: "This is an internal header file, included by other library headers. Do not attempt to use it directly."
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. The opposite of noexcept
    By Grumpulus in forum C++ Programming
    Replies: 8
    Last Post: 04-06-2015, 10:57 AM
  2. constexpr and auto references
    By koplersky in forum C++ Programming
    Replies: 4
    Last Post: 02-09-2015, 06:25 AM
  3. Replies: 1
    Last Post: 11-06-2014, 01:33 PM
  4. Constexpr and generalized constant expressions in C++11
    By webmaster in forum C++ Programming
    Replies: 8
    Last Post: 09-29-2011, 06:37 PM
  5. namespaces
    By Ancient Dragon in forum C++ Programming
    Replies: 6
    Last Post: 09-30-2005, 06:04 PM

Tags for this Thread