Skip to content
dereferencing pointer to incomplete type

dereferencing pointer to incomplete type

DodaTech 3 min read

The dereferencing pointer to incomplete type error means you are accessing a member of a forward-declared type — the compiler lacks its full definition.

What It Means

A forward declaration (e.g., struct MyType; or class MyClass;) tells the compiler a type exists but not its members. You can declare pointers to incomplete types but cannot access their members or create instances. When you try to dereference such a pointer, the compiler reports this error.

Why It Happens

  • A forward declaration was used but the full #include is missing
  • The struct or class definition is guarded and excluded by a preprocessor condition
  • Circular dependencies prevent the full definition from being visible
  • An opaque pointer (PIMPL idiom) is used without including the implementation header
  • The definition appears after the point of use in the same file

How to Fix It

Step 1: Include the full definition

// forward.h
struct Point; // forward declaration only
// main.cpp
#include "forward.h"

int main() {
    Point* p = nullptr;
    p->x = 10; // error: dereferencing pointer to incomplete type 'Point'
    return 0;
}
// point.h — full definition
#ifndef POINT_H
#define POINT_H
struct Point {
    int x;
    int y;
};
#endif
// main.cpp — fixed
#include "point.h"  // include full definition

int main() {
    Point* p = new Point{10, 20};
    p->x = 10;
    delete p;
    return 0;
}

Step 2: Check for circular includes

// a.h
#ifndef A_H
#define A_H
#include "b.h"
struct A {
    B* b_ptr;
    void doSomething();
};
#endif
// b.h
#ifndef B_H
#define B_H
#include "a.h"
struct B {
    A* a_ptr;
    int value;
};
#endif

Circular includes cause one header to see only a forward declaration. Fix: Use forward declarations in headers and include full definitions in .cpp files:

// a.h
#ifndef A_H
#define A_H
struct B; // forward declaration
struct A {
    B* b_ptr;
    void doSomething();
};
#endif
// a.cpp
#include "a.h"
#include "b.h" // full definition here
void A::doSomething() { /* uses B members */ }

Step 3: Fix the PIMPL idiom

// widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <memory>

class Widget {
public:
    Widget();
    ~Widget();
    void show();
private:
    struct Impl; // forward declaration
    std::unique_ptr<Impl> pImpl;
};
#endif
// widget.cpp
#include "widget.h"
#include <iostream>

struct Widget::Impl { // full definition
    void draw() { std::cout << "Drawing\n"; }
};

Widget::Widget() : pImpl(std::make_unique<Impl>()) {}
Widget::~Widget() = default;
void Widget::show() { pImpl->draw(); }

If you forget to define Widget::Impl in the .cpp file, you get an incomplete type error when calling pImpl->draw().

Step 4: Verify preprocessor conditions

// config.h
#ifdef ENABLE_FEATURE
struct Feature {
    int data;
};
#endif
// main.cpp
#include "config.h"
// ENABLE_FEATURE not defined!

void process(Feature* f) {
    f->data = 42; // error: incomplete type 'Feature'
}

Fix: Ensure the preprocessor define is set, or include the definition unconditionally.

Why can I declare a pointer to an incomplete type?
The compiler only needs to know the size of a pointer (fixed, e.g., 8 bytes on 64-bit) to declare it. For accessing members or creating instances, the compiler needs the full type layout. This is why forward declarations work for pointer members but not for member access.
What is the difference between forward declaration and full include?
A forward declaration (class Foo;) tells the compiler “Foo exists.” A full include provides the complete class definition with all members and sizes. Use forward declarations in headers to reduce compilation times and break circular dependencies. Use full includes in source files where you actually use the type.
How do I fix circular dependencies?
Use forward declarations in headers and move member function implementations that need the full definition to .cpp files. This breaks the cycle because headers only need pointers/references (which work with forward declarations) while .cpp files include all necessary headers.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro