Is it safe to make a const reference member to a temporary variable?

前端 未结 6 1887
太阳男子
太阳男子 2021-01-13 09:32

I\'ve tried to code like this several times:

struct Foo
{
    double const& f;
    Foo(double const& fx) : f(fx)
    {
        printf(\"%f %f\\n\", f         


        
6条回答
  •  自闭症患者
    2021-01-13 10:06

    This is indeed unsafe (it has undefined behavior), and the asan AddressSanitizerUseAfterScope will detect this:

    $ g++ -ggdb3 a.cpp -fsanitize=address -fsanitize-address-use-after-scope && ./a.out
    125.000000 125.000000
    =================================================================
    ==11748==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7fff1bbfdab0 at pc 0x000000400b80 bp 0x7fff1bbfda20 sp 0x7fff1bbfda18
    READ of size 8 at 0x7fff1bbfdab0 thread T0
        #0 0x400b7f in Foo::GetF() const a.cpp:12
        #1 0x4009ca in main a.cpp:18
        #2 0x7fac0bd05d5c in __libc_start_main (/lib64/libc.so.6+0x1ed5c)
        #3 0x400808  (a.out+0x400808)
    
    Address 0x7fff1bbfdab0 is located in stack of thread T0 at offset 96 in frame
        #0 0x4008e6 in main a.cpp:16
    
      This frame has 2 object(s):
        [32, 40) 'p'
        [96, 104) '' <== Memory access at offset 96 is inside this variable
    

    In order to use AddressSanitizerUseAfterScope, you need to run Clang 5.0 or gcc 7.1.

    Valgrind is good at detecting invalid use of heap memory, but because it runs on an unaltered program file it cannot in general detect stack use bugs.

    Your code is unsafe because the parameter double const& fx is bound to a temporary, a materialized prvalue double with value 125.0. This temporary has lifetime terminating at the end of the statement-expression Foo p(123.0 + 2.0).

    One way to make your code safe is to use aggregate lifetime extension (Extending temporary's lifetime through rvalue data-member works with aggregate, but not with constructor, why?), by removing the constructor Foo::Foo(double const&), and changing the initializer of p to use the list-initialization syntax:

    Foo p{123.0 + 2.0};
    //   ^           ^
    

提交回复
热议问题