Search code examples
c++inheritanceconstructorinitialization

Why does g++ not care that the initializer list assigns to (const std::string&) a (std::string)? and other weirdness


I encountered this problem while doing my assignments. When you have a class B that inherits class A, and B initializes variables in A by calling the constructor of A in B's constructor, the variable that is supposed to be initialized in A's constructor remains uninitialized. This doesn't seem to happen if we create an object of class A, even though seemingly the only difference is the inheritance and constructor chain.

Here is a minimal example:

#include <iostream>
#include <string>

class A {
public:
    A(std::string s)
    : s_(s) {}

    ~A(){}

    void Print() const {
        std::cout << s_ + "123";
    }
private:
    const std::string& s_;
};

class B : public A {
public:
    B(std::string s)
    : A(s) {}
};

int main()
{
  //A a = A("123");
  //a.Print();
  B b = B("123");
  b.Print();
}

In Print(), you can remove the extra string literal. This way the issue is focused on the variable not being initialized. But with the extra literal, according to valgrind, a million bytes are still reachable. This seems very weird.

Valgrind without literal in Print():

g++ -c -g -std=c++17 -Wall -Wextra -pedantic main.cpp -o main.o
g++ main.o   -o main
valgrind ./main
==22551== Memcheck, a memory error detector
==22551== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==22551== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==22551== Command: ./main
==22551==
==22551== error calling PR_SET_PTRACER, vgdb might block
==22551== Conditional jump or move depends on uninitialised value(s)
==22551==    at 0x4F4FA9A: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==
==22551== Conditional jump or move depends on uninitialised value(s)
==22551==    at 0x545C928: fwrite (iofwrite.c:35)
==22551==    by 0x4F4FB83: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==
==22551== Conditional jump or move depends on uninitialised value(s)
==22551==    at 0x54689B4: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1226)
==22551==    by 0x545C9E6: fwrite (iofwrite.c:39)
==22551==    by 0x4F4FB83: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==
==22551== Conditional jump or move depends on uninitialised value(s)
==22551==    at 0x5468A85: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1275)
==22551==    by 0x545C9E6: fwrite (iofwrite.c:39)
==22551==    by 0x4F4FB83: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==
==22551== Conditional jump or move depends on uninitialised value(s)
==22551==    at 0x5468210: _IO_file_write@@GLIBC_2.2.5 (fileops.c:1198)
==22551==    by 0x5468B9E: new_do_write (fileops.c:457)
==22551==    by 0x5468B9E: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1277)
==22551==    by 0x545C9E6: fwrite (iofwrite.c:39)
==22551==    by 0x4F4FB83: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==
==22551== Syscall param write(buf) contains uninitialised byte(s)
==22551==    at 0x54ED264: write (write.c:27)
==22551==    by 0x546822C: _IO_file_write@@GLIBC_2.2.5 (fileops.c:1203)
==22551==    by 0x5468B9E: new_do_write (fileops.c:457)
==22551==    by 0x5468B9E: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1277)
==22551==    by 0x545C9E6: fwrite (iofwrite.c:39)
==22551==    by 0x4F4FB83: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==
==22551== Syscall param write(count) contains uninitialised byte(s)
==22551==    at 0x54ED264: write (write.c:27)
==22551==    by 0x546822C: _IO_file_write@@GLIBC_2.2.5 (fileops.c:1203)
==22551==    by 0x5468B9E: new_do_write (fileops.c:457)
==22551==    by 0x5468B9E: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1277)
==22551==    by 0x545C9E6: fwrite (iofwrite.c:39)
==22551==    by 0x4F4FB83: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==
==22551== Syscall param write(buf) points to uninitialised byte(s)
==22551==    at 0x54ED264: write (write.c:27)
==22551==    by 0x546822C: _IO_file_write@@GLIBC_2.2.5 (fileops.c:1203)
==22551==    by 0x5468B9E: new_do_write (fileops.c:457)
==22551==    by 0x5468B9E: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1277)
==22551==    by 0x545C9E6: fwrite (iofwrite.c:39)
==22551==    by 0x4F4FB83: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==  Address 0x1ffefff910 is on thread 1's stack
==22551==  in frame #5, created by A::Print() const (main.cpp:14)
==22551==
==22551== Conditional jump or move depends on uninitialised value(s)
==22551==    at 0x5468BB0: new_do_write (fileops.c:458)
==22551==    by 0x5468BB0: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1277)
==22551==    by 0x545C9E6: fwrite (iofwrite.c:39)
==22551==    by 0x4F4FB83: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==
==22551== Conditional jump or move depends on uninitialised value(s)
==22551==    at 0x5468BEB: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1279)
==22551==    by 0x545C9E6: fwrite (iofwrite.c:39)
==22551==    by 0x4F4FB83: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==
==22551== Conditional jump or move depends on uninitialised value(s)
==22551==    at 0x545CA65: fwrite (iofwrite.c:45)
==22551==    by 0x4F4FB83: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==
==22551== Conditional jump or move depends on uninitialised value(s)
==22551==    at 0x545CA6A: fwrite (iofwrite.c:45)
==22551==    by 0x4F4FB83: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==
==22551== Conditional jump or move depends on uninitialised value(s)
==22551==    at 0x4F4FB91: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==22551==    by 0x109BAF: A::Print() const (main.cpp:15)
==22551==    by 0x1099EB: main (main.cpp:32)
==22551==
==22551==
==22551== HEAP SUMMARY:
==22551==     in use at exit: 0 bytes in 0 blocks
==22551==   total heap usage: 2 allocs, 2 frees, 73,216 bytes allocated
==22551==
==22551== All heap blocks were freed -- no leaks are possible
==22551==
==22551== For counts of detected and suppressed errors, rerun with: -v
==22551== Use --track-origins=yes to see where uninitialised values come from
==22551== ERROR SUMMARY: 13 errors from 13 contexts (suppressed: 0 from 0)

Valgrind with literal in Print():

(I had to cut the middle out to fit into the character limit, the whole thing is here: https://pastebin.com/UQmB0mXj)

g++ -c -g -std=c++17 -Wall -Wextra -pedantic main.cpp -o main.o
g++ main.o   -o main
valgrind ./main
==22561== Memcheck, a memory error detector
==22561== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==22561== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==22561== Command: ./main
==22561==
==22561== error calling PR_SET_PTRACER, vgdb might block
==22561== Conditional jump or move depends on uninitialised value(s)
==22561==    at 0x10AC50: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) (basic_string.tcc:217)
==22561==    by 0x10A7DD: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char*>(char*, char*, std::__false_type) (basic_string.h:236)
==22561==    by 0x10A472: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*) (basic_string.h:255)
==22561==    by 0x10A15B: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:440)
==22561==    by 0x10A05E: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*) (basic_string.h:5928)
==22561==    by 0x109E66: A::Print() const (main.cpp:15)
==22561==    by 0x109C8B: main (main.cpp:32)
==22561==
==22561== Conditional jump or move depends on uninitialised value(s)
==22561==    at 0x10AD84: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create(unsigned long&, unsigned long) (basic_string.tcc:137)
==22561==    by 0x10AC69: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) (basic_string.tcc:219)
==22561==    by 0x10A7DD: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char*>(char*, char*, std::__false_type) (basic_string.h:236)
==22561==    by 0x10A472: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*) (basic_string.h:255)
==22561==    by 0x10A15B: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:440)
==22561==    by 0x10A05E: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*) (basic_string.h:5928)
==22561==    by 0x109E66: A::Print() const (main.cpp:15)
==22561==    by 0x109C8B: main (main.cpp:32)
==22561==
...
had to cut here to fit into character limit
...
==22561==
==22561== Conditional jump or move depends on uninitialised value(s)
==22561==    at 0x10A9F0: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy(char*, char const*, unsigned long) (basic_string.h:337)
==22561==    by 0x10AED7: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy_chars(char*, char*, char*) (basic_string.h:382)
==22561==    by 0x10ACB0: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) (basic_string.tcc:225)
==22561==    by 0x10A7DD: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char*>(char*, char*, std::__false_type) (basic_string.h:236)
==22561==    by 0x10A472: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*) (basic_string.h:255)
==22561==    by 0x10A15B: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:440)
==22561==    by 0x10A05E: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*) (basic_string.h:5928)
==22561==    by 0x109E66: A::Print() const (main.cpp:15)
==22561==    by 0x109C8B: main (main.cpp:32)
==22561==
==22561== Conditional jump or move depends on uninitialised value(s)
==22561==    at 0x109DE1: std::char_traits<char>::copy(char*, char const*, unsigned long) (char_traits.h:348)
==22561==    by 0x10AA1D: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy(char*, char const*, unsigned long) (basic_string.h:340)
==22561==    by 0x10AED7: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy_chars(char*, char*, char*) (basic_string.h:382)
==22561==    by 0x10ACB0: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) (basic_string.tcc:225)
==22561==    by 0x10A7DD: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char*>(char*, char*, std::__false_type) (basic_string.h:236)
==22561==    by 0x10A472: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*) (basic_string.h:255)
==22561==    by 0x10A15B: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:440)
==22561==    by 0x10A05E: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*) (basic_string.h:5928)
==22561==    by 0x109E66: A::Print() const (main.cpp:15)
==22561==    by 0x109C8B: main (main.cpp:32)
==22561==
==22561== Conditional jump or move depends on uninitialised value(s)
==22561==    at 0x4C366E6: memmove (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22561==    by 0x109E05: std::char_traits<char>::copy(char*, char const*, unsigned long) (char_traits.h:350)
==22561==    by 0x10AA1D: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy(char*, char const*, unsigned long) (basic_string.h:340)
==22561==    by 0x10AED7: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy_chars(char*, char*, char*) (basic_string.h:382)
==22561==    by 0x10ACB0: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) (basic_string.tcc:225)
==22561==    by 0x10A7DD: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char*>(char*, char*, std::__false_type) (basic_string.h:236)
==22561==    by 0x10A472: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*) (basic_string.h:255)
==22561==    by 0x10A15B: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:440)
==22561==    by 0x10A05E: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*) (basic_string.h:5928)
==22561==    by 0x109E66: A::Print() const (main.cpp:15)
==22561==    by 0x109C8B: main (main.cpp:32)
==22561==
==22561== Conditional jump or move depends on uninitialised value(s)
==22561==    at 0x4C36711: memmove (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22561==    by 0x109E05: std::char_traits<char>::copy(char*, char const*, unsigned long) (char_traits.h:350)
==22561==    by 0x10AA1D: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy(char*, char const*, unsigned long) (basic_string.h:340)
==22561==    by 0x10AED7: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy_chars(char*, char*, char*) (basic_string.h:382)
==22561==    by 0x10ACB0: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) (basic_string.tcc:225)
==22561==    by 0x10A7DD: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char*>(char*, char*, std::__false_type) (basic_string.h:236)
==22561==    by 0x10A472: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*) (basic_string.h:255)
==22561==    by 0x10A15B: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:440)
==22561==    by 0x10A05E: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*) (basic_string.h:5928)
==22561==    by 0x109E66: A::Print() const (main.cpp:15)
==22561==    by 0x109C8B: main (main.cpp:32)
==22561==
==22561== Conditional jump or move depends on uninitialised value(s)
==22561==    at 0x4C367EE: memmove (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22561==    by 0x109E05: std::char_traits<char>::copy(char*, char const*, unsigned long) (char_traits.h:350)
==22561==    by 0x10AA1D: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy(char*, char const*, unsigned long) (basic_string.h:340)
==22561==    by 0x10AED7: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy_chars(char*, char*, char*) (basic_string.h:382)
==22561==    by 0x10ACB0: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) (basic_string.tcc:225)
==22561==    by 0x10A7DD: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char*>(char*, char*, std::__false_type) (basic_string.h:236)
==22561==    by 0x10A472: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*) (basic_string.h:255)
==22561==    by 0x10A15B: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:440)
==22561==    by 0x10A05E: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*) (basic_string.h:5928)
==22561==    by 0x109E66: A::Print() const (main.cpp:15)
==22561==    by 0x109C8B: main (main.cpp:32)
==22561==
==22561== Invalid read of size 8
==22561==    at 0x4C367EE: memmove (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22561==    by 0x109E05: std::char_traits<char>::copy(char*, char const*, unsigned long) (char_traits.h:350)
==22561==    by 0x10AA1D: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy(char*, char const*, unsigned long) (basic_string.h:340)
==22561==    by 0x10AED7: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy_chars(char*, char*, char*) (basic_string.h:382)
==22561==    by 0x10ACB0: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) (basic_string.tcc:225)
==22561==    by 0x10A7DD: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char*>(char*, char*, std::__false_type) (basic_string.h:236)
==22561==    by 0x10A472: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*) (basic_string.h:255)
==22561==    by 0x10A15B: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:440)
==22561==    by 0x10A05E: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*) (basic_string.h:5928)
==22561==    by 0x109E66: A::Print() const (main.cpp:15)
==22561==    by 0x109C8B: main (main.cpp:32)
==22561==  Address 0x1fff001000 is not stack'd, malloc'd or (recently) free'd
==22561==
==22561==
==22561== Process terminating with default action of signal 11 (SIGSEGV)
==22561==  Access not within mapped region at address 0x1FFF001000
==22561==    at 0x4C367EE: memmove (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22561==    by 0x109E05: std::char_traits<char>::copy(char*, char const*, unsigned long) (char_traits.h:350)
==22561==    by 0x10AA1D: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy(char*, char const*, unsigned long) (basic_string.h:340)
==22561==    by 0x10AED7: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy_chars(char*, char*, char*) (basic_string.h:382)
==22561==    by 0x10ACB0: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) (basic_string.tcc:225)
==22561==    by 0x10A7DD: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char*>(char*, char*, std::__false_type) (basic_string.h:236)
==22561==    by 0x10A472: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*) (basic_string.h:255)
==22561==    by 0x10A15B: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:440)
==22561==    by 0x10A05E: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*) (basic_string.h:5928)
==22561==    by 0x109E66: A::Print() const (main.cpp:15)
==22561==    by 0x109C8B: main (main.cpp:32)
==22561==  If you believe this happened as a result of a stack
==22561==  overflow in your program's main thread (unlikely but
==22561==  possible), you can try to increase the size of the
==22561==  main thread stack using the --main-stacksize= flag.
==22561==  The main thread stack size used in this run was 8388608.
==22561==
==22561== HEAP SUMMARY:
==22561==     in use at exit: 1,089,515 bytes in 1 blocks
==22561==   total heap usage: 2 allocs, 1 frees, 1,162,219 bytes allocated
==22561==
==22561== LEAK SUMMARY:
==22561==    definitely lost: 0 bytes in 0 blocks
==22561==    indirectly lost: 0 bytes in 0 blocks
==22561==      possibly lost: 0 bytes in 0 blocks
==22561==    still reachable: 1,089,515 bytes in 1 blocks
==22561==         suppressed: 0 bytes in 0 blocks
==22561== Rerun with --leak-check=full to see details of leaked memory
==22561==
==22561== For counts of detected and suppressed errors, rerun with: -v
==22561== Use --track-origins=yes to see where uninitialised values come from
==22561== ERROR SUMMARY: 197 errors from 12 contexts (suppressed: 0 from 0)
src.make:32: recipe for target 'valgrind-run' failed
make: *** [valgrind-run] Segmentation fault (core dumped)

My questions are:

  1. Why does the compiler not give an error because of A's constructor? How can we set a reference with the value?

  2. Why does this only give errors when there is inheritance involved?

  3. Why does adding a literal in Print() have such a big effect? And why are a million bytes allocated because of this?


Solution

    1. Why does the compiler not give an error because of A's constructor?

    Presumably because A's constructor is well-formed, and thus the compiler must accept it in order to conform to the standard.

    You are allowed to bind a reference to a local variable. The reference will be invalid after the constructor returns, but if the program never indirects through the reference after returning from the constructor, then that is technically no problem. It is not trivial for the compiler to prove that the program will do that (this problem is generally analogous to the halting problem).

    A compiler does warn about it through:

    warning: binding reference member 's_' to stack allocated parameter 's' [-Wdangling-field]


    How can we set a reference with the value?

    You have bound the reference to the local variable. It is unclear what you're trying to do, but probably you should not be using a reference member to achieve that.


    1. Why ...
    1. Why ...

    Because behaviour of the program is undefined. Any change can affect the behaviour of the program in any way. The behaviour can even change without change to the program. Or it might not change. Nothing about the behaviour of the program is guaranteed.