[ 
https://issues.apache.org/jira/browse/MESOS-2629?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Adam B updated MESOS-2629:
--------------------------
    Sprint: Mesosphere Q2 Sprint 8 - 5/1, Mesosphere Q1 Sprint 9 - 5/15, 
Mesosphere Q1 Sprint 10 - 5/30  (was: Mesosphere Q2 Sprint 8 - 5/1, Mesosphere 
Q1 Sprint 9 - 5/15)

> Update style guide to disallow capture by reference of temporaries
> ------------------------------------------------------------------
>
>                 Key: MESOS-2629
>                 URL: https://issues.apache.org/jira/browse/MESOS-2629
>             Project: Mesos
>          Issue Type: Task
>          Components: documentation, technical debt
>            Reporter: Joris Van Remoortere
>            Assignee: Joris Van Remoortere
>
> We modify the style guide to disallow constant references to temporaries as a 
> whole. This means disallowing both (1) and (2) below.
> h3. Background
> 1. Constant references to simple expression temporaries do extend the 
> lifetime of the temporary till end of function scope:
> * Temporary returned by function:
>   {code}
>   // See full example below.
>   T f(const char* s) { return T(s); }
>   {
>     const T& good = f("Ok");
>     // use of good is ok.
>   }
>   {code}
> * Temporary constructed as simple expression:
>   {code}
>   // See full example below.
>   {
>     const T& good = T("Ok");
>     // use of good is ok.
>   }
>   {code}
> 2. Constant references to expressions that result in a reference to a 
> temporary do not extend the lifetime of the temporary:
>   * Temporary returned by function:
>   {code}
>   // See full example below.
>   T f(const char* s) { return T(s); }
>   {
>     const T& bad = f("Bad!").Member();
>     // use of bad is invalid.
>   }
>   {code}
>   * Temporary constructed as simple expression:
>   {code}
>   // See full example below.
>   {
>     const T& bad = T("Bad!").Member();
>     // use of bad is invalid.
>   }
>   {code}
> h3. Mesos Case
>   - In Mesos we use Future<T> a lot. Many of our functions return Futures by 
> value:
>   {code}
>   class Socket {
>     Future<Socket> accept();
>     Future<size_t> recv(char* data, size_t size);
>     ...
>   }
>   {code}
>   - Sometimes we capture these Futures:
>   {code}
>   {
>     const Future<Socket>& accepted = socket.accept(); // Valid c++, propose 
> we disallow.
>   }
>   {code}
>   - Sometimes we chain these Futures:
>   {code}
>   {
>     socket.accept().then(lambda::bind(_accepted)); // Temporary will be valid 
> during 'then' expression evaluation.
>   }
>   {code}
>   - Sometimes we do both:
>   {code}
>   {
>     const Future<Socket>& accepted = 
> socket.accept().then(lambda::bind(_accepted)); // Dangerous! 'accepted' 
> lifetime will not be valid till end of scope. Disallow!
>   }
>   {code}
> h3. Reasoning
> - Although (1) is ok, and considered a 
> [feature|http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/],
>  (2) is extremely dangerous and leads to hard to track bugs.
> - If we explicitly allow (1), but disallow (2), then my worry is that someone 
> coming along to maintain the code later on may accidentally turn (1) into 
> (2), without recognizing the severity of this mistake. For example:
> {code}
> // Original code:
> const T& val = T();
> std::cout << val << std::endl;
> // New code:
> const T& val = T().removeWhiteSpace();
> std::cout << val << std::endl; // val could be corrupted since the destructor 
> has been invoked and T's memory freed.
> {code}
> - If we disallow both cases: it will be easier to catch these mistakes early 
> on in code reviews (and avoid these painful bugs), at the same cost of 
> introducing a new style guide rule.
> h3. Performance Implications
> - BenH suggests c++ developers are commonly taught to capture by constant 
> reference to hint to the compiler that the copy can be elided.
> - Modern compilers use a Data Flow Graph to make optimizations such as
>   - *In-place-construction*: leveraged by RVO and NRVO to construct the 
> object in place on the stack. Similar to "*Placement new*": 
> http://en.wikipedia.org/wiki/Placement_syntax
>   - *RVO* (Return Value Optimization): 
> http://en.wikipedia.org/wiki/Return_value_optimization
>   - *NRVO* (Named Return Value Optimization): 
> https://msdn.microsoft.com/en-us/library/ms364057%28v=vs.80%29.aspx
> - Since modern compilers perform these optimizations, we no longer need to 
> 'hint' to the compiler that the copies can be elided.
> h3. Example program
> {code}
> #include <stdio.h>
> class T {
> public:
>   T(const char* str) : Str(str) {
>     printf("+ T(%s)\n", Str);
>   }
>   ~T() {
>     printf("- T(%s)\n", Str);
>   }
>   const T& Member() const
>   {
>     return *this;
>   }
> private:
>   const char* Str;
> };
> T f(const char* s) { return T(s); }
> int main() {
>   const T& good = T("Ok");
>   const T& good_f = f("Ok function");
>   const T& bad = T("Bad!").Member();
>   const T& bad_f = T("Bad function!").Member();
>   printf("End of function scope...\n");
> }
> {code}
> Output:
> {code}
> + T(Ok)
> + T(Ok function)
> + T(Bad!)
> - T(Bad!)
> + T(Bad function!)
> - T(Bad function!)
> End of function scope...
> - T(Ok function)
> - T(Ok)
> {code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to