Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::vector on forward declared type

The following code seems to work correctly on Clang++ and GCC:

#include <vector>

class A {
private:
    int i;
    std::vector<A> children;
public:
    A& add();
};

A& A::add() { children.emplace_back(); return children.back(); }

int main() {
    A a;
    A& a2 = a.add();
}

When the data member std::vector<A> is declared, A is still an incomplete type. Same when using std::vector<B> and B was only forward declared with class B;. It should work with std::vector since it only contains a pointer-to-A.

Is this guaranteed to work, or undefined behavior?

like image 270
tmlen Avatar asked Jun 25 '15 10:06

tmlen


People also ask

Can you forward declare reference C++?

class C { public: void mutator(int x) { myValue = x; } int accessor() const { return myValue; } private: int myValue; }; In this example, there are two references to myValue before it is declared. C++ generally prohibits forward references, but they are allowed in the special case of class members.

How do you forward a declaration function in C++?

To write a forward declaration for a function, we use a function declaration statement (also called a function prototype). The function declaration consists of the function header (the function's return type, name, and parameter types), terminated with a semicolon. The function body is not included in the declaration.

Why Forward declare instead of include?

A forward declaration is much faster to parse than a whole header file that itself may include even more header files. Also, if you change something in the header file for class B, everything including that header will have to be recompiled.

Can you forward declare a namespace?

There is no forward declaration of namespace.


1 Answers

This is undefined behavior in C++14 and earlier; well-defined in C++17 (if it's 17).

[res.on.functions]/p2, bullet 2.7:

In particular, the effects are undefined in the following cases:

  • [...]
  • if an incomplete type (3.9) is used as a template argument when instantiating a template component, unless specifically allowed for that component.

In C++14 and earlier, std::vector does not "specifically allow" this. So the behavior is undefined.

For C++17, N4510, adopted at the committee's May 2015 meeting, relaxes this rule for vector, list, and forward_list.

like image 129
T.C. Avatar answered Oct 04 '22 16:10

T.C.