2

I am doing some tests with trivial types with copy elision. As my prior question : Copy elision and trivially copyable types

The following code works well for std::string but does not for const char*. Valgrind returns me "use of uninitialized value of size 8.

#include <iostream>
#include <string>

template <typename T> struct Object {
private:
  T obj = "My name is John Doe and I am an handsome beautiful guy of 178 years "
          "old loullll !!!";

public:
  T *ptr;

  Object() { ptr = &obj; }
};

Object<const char *> f1() { return {}; }

Object<std::string> f2() { return {}; }

int main() {
  {
    auto x = f2();
    std::cout << *x.ptr << std::endl;
  }

  {
    auto x = f1();
    std::cout << *x.ptr << std::endl;
  }
}

Since copy elision should happen in both cases, I don't understand why it does not work with both cases...

However, using this definition for object make things working (because I think, object becomes not trivially copyable)

template <typename T> struct Object {
private:
  T obj = "My name is John Doe and I am an handsome beautiful guy of 178 years "
          "old loullll !!!";

public:
  T *ptr;

// notice the destructor
  ~Object() {}
  Object() { ptr = &obj; }
};

Evg
  • 25,259
  • 5
  • 41
  • 83
Antoine Morrier
  • 3,930
  • 16
  • 37
  • I know. And it works perfectly. The issue with the const char version – Antoine Morrier May 04 '21 at 10:08
  • 1
    No compiler bug. `Object` was never really trivially copyable. It simply violated the rule of 0/3/5 and let the compiler think it was. So the compiler made wrong ABI choices (as mentioned in the answer to your previous post) – StoryTeller - Unslander Monica May 04 '21 at 10:13
  • Why with a custom destructor, the compiler did the good choice ? – Antoine Morrier May 04 '21 at 10:17
  • 4
    Because of the very paragraph you cited in your previous question. It mentions the member functions that appear in the rule of 0/3/5 for a reason. Any one of those makes the type suspect as not passable in a register. Also, it's not a matter of right or wrong choice. `Object` is buggy. It doesn't maintain its invariants. The compiler's choice should be immaterial. – StoryTeller - Unslander Monica May 04 '21 at 10:22
  • That's difficult to me to understand. I think I have to re read it several times ahaha. But if the type can be passed in a register, it does not mean that it can avoid copy elision ? (Which explains the fact that I got an invalid read here ?) – Antoine Morrier May 04 '21 at 10:34
  • Are you sure you're compiling with C++17? Would you mind printing `this` in ctor and `&x`? – yeputons May 04 '21 at 11:10
  • 2
    _But if the type can be passed in a register, it does not mean that it can avoid copy elision ?_ The fact that an object is passed in registers means that a temporary object has been created and what is passed is its copy. – Language Lawyer May 04 '21 at 11:27

0 Answers0