Is it undefined behavior to pass a pointer to an unconstructed streambuf object to the ostream constructor?

Question

Does the following program have undefined behavior?

#include <iostream>          // std::{ostream, streambuf}

// The streambuf ctor is protected so we need a wrapper to create one.
struct mystreambuf : public std::streambuf {};

extern mystreambuf sb;       // Not yet constructed.
std::ostream os(&sb);        // Passing "invalid" pointer here?  UB?
mystreambuf sb;              // Now it is constructed.

int main() { return 0; }

It invokes the ostream constructor, passing a pointer to a
streambuf object whose lifetime has not yet begun
(basic.life p1).
Does this constitute undefined behavior?

Attempted answer

If streambuf were a user-written class, then
class.cdtor p1
would govern, which says:

For an object with a non-trivial constructor, referring to any
non-static member or base class of the object before the constructor
begins execution results in undefined behavior. […]

This language, and its accompanying example, make it clear that merely
taking the address of an unconstructed object is not undefined. As far
I can tell, passing that address as a pointer to a user-written function
that only stores its value and tests it against nullptr is also not
undefined.

But streambuf is a library class, so instead
res.on.arguments p1
applies, which says, in part:

If an argument to a function has an invalid value (such as a value
outside the domain of the function or a pointer invalid for its
intended use), the behavior is undefined.

But what constitutes an “invalid value”? Presumably we have to
determine the “intended use” by reading the specification of the called
function. The constructor spec
ostream.cons p1 says in part:

Effects: Initializes the base class subobject with
basic_ios<charT, traits>::init(sb) ([basic.ios.cons]).

The spec for init
basic.ios.cons p4 says:

Postconditions: The postconditions of this function are indicated in
Table 127.

where Table 127 has two rows that mention sb:

Element    Value
-------    -----
rdbuf()    sb
rdstate()  goodbit if sb is not a null pointer, otherwise badbit.

So, at first glance, this would seem to suggest that sb is only stored
(so that rdbuf() can return it) and tested for being nullptr; and
that these together comprise its “intended use”. Since both of these
would be legal for user-written code to do, it is legal to pass the
pointer in question, so the program has defined behavior.

But Table 127 is merely a list of postconditions. It does not
definitively assert that nothing else is in the scope of “intended use”.
For that, it would seem necessary to exhaustively review everything that
basic_ostream and its subclasses potentially do with sb.

While attempting to do so, I find imbue at
basic.ios.members p9:

Effects: Calls ios_base::imbue(loc) and if rdbuf() != 0 then
rdbuf()->pubimbue(loc).

Clearly, calling rdbuf()->pubimbue(loc) before the object pointed to
by rdbuf() is constructed is undefined. Do we call imbue? Not
explicitly of course, and there’s no particular reason to suspect an
indirect call either, but the existence of this behavior arguably puts
it in scope of the “intended use” of the pointer passed to the
constructor, since eventually it could be used this way. Furthermore,
would it necessarily be non-conforming for an implementation to call
imbue on its own during the ostream constructor? I don’t see why it
would be, and if an implementation is free to call imbue in the
constructor, then clearly we have undefined behavior. And there could
be other methods that suggest other usages, as my survey was by no means
complete.

Now, in a comment on an
answer
to a related question, indi observes that the Clang implementation of
std::basic_fstream does pass a pointer to an unconstructed member
object to the iostream constructor at
fstream:1419:

  basic_filebuf<char_type, traits_type> __sb_;
};

template <class _CharT, class _Traits>
inline basic_fstream<_CharT, _Traits>::basic_fstream() : basic_iostream<char_type, traits_type>(&__sb_) {}

But this example is not definitive because (1) it could be a mistake,
and (2) the library implementation is generally allowed to do things
that would be undefined in user code. Nevertheless, it is at least weak
evidence that the Clang developers think the practice does not have
undefined behavior, as they have no reason in this case to write code
that relies on the library’s license to bend the rules, since it would
be a trivial change to instead pass nullptr to the constructor and
then in the body call init with the address of the (now fully
constructed) member object.

Ultimately, it seems to me that the language specification is ambiguous,
as it relies on the terms “invalid value” and “intended use” which are
not clearly specified. But perhaps someone can identify a provision I
have missed or an error in my interpretations.

Related questions

While researching this, I came across some existing questions
that seemed related. The question
How to inherit from std::ostream?
has three relevant answers:

  • The (highest-voted)
    answer by Ben was
    specifically edited to avoid the potential problem by ensuring the
    streambuf is constructed before passing its address.

  • A more recent
    answer by mach6 also
    goes out of its way to avoid passing the unconstructed object’s
    pointer, this time by initializing the ostream with nullptr
    (albeit by using a non-standard constructor that only GNU libc++ has,
    but is easily replaced with a standard one) and then calling init
    afterward.

  • The answer by
    Henrik Heino passes the not-yet-constructed pointer. But this answer
    does not claim to be correct, and has one comment that says passing
    the pointer that way is incorrect.

From these answers and comments, I infer that quite a few knowledgeable
people believe that the example at the top of this question has
undefined behavior.

Meanwhile, the question
Is it dangerous to pass a pointer to a subobject that is not constructed yet to a constructor of another subobject during the object construction?
is very nearly the same as mine, but is marred by having some important
parts of the example code missing, and involves an extraneous
AnotherClass that further muddies the question. The
answer by aschepler
seems to say that the practice is ok in general, but not in the OP’s
case because of AnotherClass, but it only reasons as if all of the
code were written by the user, ignoring the library aspect.

Finally, the question
Is it safe to pass an unconstructed buffer to the constructor of std::ostream?
is essentially the same as mine–I’m asking a duplicate! Why? In
short, that question has no answers, and I think the additional research
in my question makes it more likely mine can be answered, so I’m
effectively submitting this with the intention of replacing that one.
I asked a
meta question
about whether asking this duplicate is acceptable, and the consensus
seems to be that is.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật