Search code examples
c++undefined-behavioriomanip

Does put_money hold its argument by value or reference?


Does the following invoke undefined behavior?

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <experimental/iterator>

int main() {
    long double values[] = {1, 2, 3};
    std::transform(
        std::begin(values), std::end(values),
        std::experimental::make_ostream_joiner(std::cout, ", "),
        [](long double v) {
            return std::put_money(v + 1);
        }
    );
    return 0;
}

My worry is that return std::put_money(v + 1) returns a reference to the temporary v + 1.


Solution

  • The standard ([ext.manip]/6) only defines this specific expression:

    out << put_­money(mon, intl);
    

    It is unspecified how mon is stored in the mean time, and it is definitely possible for it to become a dangling reference and be UB.

    An "easy" fix is making your own class to know you store the value:

    struct money_putter {
        long double value;
    
        template<class charT, class traits>
        friend std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const money_putter& mon) {
            return os << std::put_money(mon.value);
        }
    };
    
    
    int main() {
        int values[] = {1, 2, 3};
        std::transform(
            std::begin(values), std::end(values),
            std::experimental::make_ostream_joiner(std::cout, ", "),
            [](int i)  {
                return money_putter{i};  // or i + 1
            }
        );
        return 0;
    }