Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Potential C++ compiler optimization with/without throw/noexcept function

Assume the following class:

class Example
{
public:
...
    Example& operator=(const Example& rhs);
...
private:
    other_type *m_content;
    size_t m_content_size;
}

Example& Example::operator=(const Example& rhs)
{
    if (this != &rhs)
    {
        delete m_content;
        m_content = nullptr;
        m_content = getCopiedContent(rhs);
    }

    return *this;
}

I know that this is not the best way to implement operator= but that's on purpose, because my question is about these two lines:

    m_content = nullptr;
    m_content = getCopiedContent(rhs);

Can be that the compiler will optimize out m_content = nullptr; even though getCopiedContent is not defined as throw() or noexcept:

other_type* getCopiedContent(const Example& obj);

On one hand the compiler may assume that if right after m_content = nullptr; I overwrite the value of m_content with the return value of getCopiedContent, it may optimize out the whole m_content = nullptr; expression. On the other hand if the compiler optimizes it out and getCopiedContent throws an exception, m_content will contain a non valid value.

Does C++ standard state anything regarding such scenario?

like image 967
Alex Lop. Avatar asked Nov 09 '15 13:11

Alex Lop.


People also ask

Does Noexcept make code faster?

If an exception is not supposed to be thrown, the program cannot be assumed to cope with the error and should be terminated as soon as possible. Declaring a function noexcept helps optimizers by reducing the number of alternative execution paths. It also speeds up the exit after failure.

What happens when Noexcept function throws?

noexcept means that a function will not throw, not that it cannot throw, and the penalty for failure to comply is calling std::terminate , not UB.

What is the purpose of Noexcept?

noexcept is primarily used to allow "you" to detect at compile-time if a function can throw an exception. Remember: most compilers don't emit special code for exceptions unless it actually throws something.

Can be declared Noexcept?

C26440 DECLARE_NOEXCEPT "Function can be declared 'noexcept'." If code is not supposed to cause any exceptions, it should be marked as such by using the 'noexcept' specifier. This would help to simplify error handling on the client code side, as well as enable compiler to do additional optimizations.


1 Answers

Can be that the compiler will optimize out m_content = nullptr; even though getCopiedContent is not defined as throw() or noexcept:

Yes. This is a redundant operation with no side-effects. Any self-respecting compiler will optimise the redundant store away. In fact you'll have to work really hard to keep the redundant store from being optimised out, such as:

  1. make it std::atomic (if it's atomic, writes are obliged to to transmitted to other threads)
  2. make it volatile
  3. surround the write with some kind of memory barrier (e.g. lock a std::mutex) for the same reasons as (1)

On the other hand if the compiler optimizes it out and getCopiedContent throws an exception, m_content will contain a non valid value

Good observation. The compiler is permitted to perform the write of nullptr in the exception handler. i.e. it may re-order instructions in order to save operations provided the total outcome was 'as if' it did not.

Does C++ standard states anything regarding such scenario?

Yes. It has the 'as-if' rule. While reasoning about one thread, the visible outcome must be 'as-if' each of your statements were executed sequentially with no optimisations against a non-pipelined, non-cached, very simple memory model. Note that no computer produced in the past 20 years is actually this simple, but the outcome of the program must be as if it were.

There is one exception to this - copy elision. Side effects of eliding redundant copies under certain circumstances do not need to be preserved. For example, while eliding copies of arguments that are temporaries and during RVO.

like image 200
Richard Hodges Avatar answered Nov 05 '22 21:11

Richard Hodges