Date
2008-05-03.00:00:00
Message id
1801

Content

Consider the following example:

    struct A {
      A() {
        std::thread(&A::Func, this).detach();
      }
      virtual void Func() {
        printf("In A");
      }
    };

    struct B : public A {
      virtual void Func() {
        printf("In B");
      }
    };

    struct C : public B {
      virtual void Func() {
        printf("In C");
      }
    };

    C c;

What is the program allowed to print? Should it be undefined behavior or merely unspecified which of the Func()s is called?

There is a related question about which variables C::Func() can depend on having been constructed. Unless we want to require the equivalent of at least memory_order_consume on the presumed virtual function table pointer, I think the answer is just the members of A.

If I instead just have

    A a;

I think the only reasonable behavior is to print In A.

Finally, given

    struct F {
      F() {
        std::thread(&F::Func, this).detach();
      }
      virtual void Func() {
        print("In F");
      }
    };

    struct G : public F {
    };

    G g;

I can see the behavior being undefined, but I think a lot of people would be confused if it did anything other than print In F.

Suggested resolution:

I think the intent here is that an object should not be used in another thread until any non-trivial constructor has been called. One possible way of saying that would be to add a new paragraph at the end of 11.9.5 [class.cdtor]:

A constructor for a class with virtual functions or virtual base classes modifies a memory location in the object that is accessed by any access to a virtual function or virtual base class or by a dynamic_cast. [Note: This implies that access to an object by another thread while it is being constructed often introduces a data race (see 6.9.2 [intro.multithread]). —end note]