user2485710
user2485710

Reputation: 9801

The lifetime and the use of rdbuf

The following code works and it doesn't look like it's offering some bad or unwanted behaviour, like undefined behaviour or an incorrect result. The code works as expected, my point is: why ?

std::vector<char> v{std::istreambuf_iterator<char>{
                         std::ifstream{"yourFile.txt", std::ios::in}.rdbuf()},
                     std::istreambuf_iterator<char>{}}; 

this is a call to the constructor of std::vector that works with iterators, my point is about the lifetime of that rdbuf() call, and the fact that rdbuf is a pointer not an object, you can't just copy rdbuf and pretend that it will always reach the content of your file, nor you can really copy the entire content of the file without using iterators.

What I was expecting is :

I'm surprised that this thing works, someone can illustrate why I'm wrong and what is happening step by step ? The ifstream object shouldn't be RAII compliant and present only in the scope of the istreambuf_iterator ?

Upvotes: 0

Views: 183

Answers (1)

Casey
Casey

Reputation: 42564

Temporary objects (when not lifetime-extended by binding to a reference) are destroyed at the end of the enclosing full-expression (C++11 12.2/3):

When an implementation introduces a temporary object of a class that has a non-trivial constructor (12.1, 12.8), it shall ensure that a constructor is called for the temporary object. Similarly, the destructor shall be called for a temporary with a non-trivial destructor (12.4). Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression.

Per 1.9/10:

A full-expression is an expression that is not a subexpression of another expression. [ Note: in some contexts, such as unevaluated operands, a syntactic subexpression is considered a full-expression (Clause 5). —end note ] If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition. A call to a destructor generated at the end of the lifetime of an object other than a temporary object is an implicit full-expression. Conversions applied to the result of an expression in order to satisfy the requirements of the language construct in which the expression appears are also considered to be part of the full-expression.

Your declaration of v "produces an implicit call of a function": the two-iterator vector constructor. It is therefore considered to be a full-expression, so the temporary ifstream object - not to mention the two temporary std::istreambuf_iterator<char> objects - is not destroyed until after the constructor call completes.

Upvotes: 3

Related Questions