What are the dangers of forward declarations?

前端 未结 9 1427
轻奢々
轻奢々 2021-02-01 16:58

I just had an interview. I was asked what is a \"forward declaration\". I was then asked if they were dangers associated with forward declarations.

I could not answer to

相关标签:
9条回答
  • 2021-02-01 17:10

    I came across an interesting snippet in the Google C++ Style Guide

    The danger they point to arises from implementing functions on incomplete types. Normally, this the compiler would throw an error, but because these are pointers, it can slip through the net.

    It can be difficult to determine whether a forward declaration or a full #include is needed. Replacing an #include with a forward declaration can silently change the meaning of code:

    // b.h:
    struct B {};
    struct D : B {};
    
    // good_user.cc:
    #include "b.h"
    void f(B*);
    void f(void*);
    void test(D* x) { f(x); }  // calls f(B*)
    

    If the #include was replaced with forward decls for B and D, test() would call f(void*).

    0 讨论(0)
  • 2021-02-01 17:12

    The only danger of forward-declaring something is when you do the forward declaration outside of a header or in a non-shared header, and the signature of the forward declaration differs from the actual signature of whatever being forward-declared. If you do it in extern "C", there would be no name mangling to check the signature at link time, so you may end up with undefined behavior when the signatures do not match.

    0 讨论(0)
  • 2021-02-01 17:13

    The first way is to reorder our function calls so add is defined before main:

    That way, by the time main() calls add(), it will already know what add is. Because this is such a simple program, this change is relatively easy to do. However, in a large program, it would be extremely tedious trying to decipher which functions called which other functions so they could be declared in the correct order.

    0 讨论(0)
  • 2021-02-01 17:14

    If a pointer to incomplete class type is passed to delete, an operator delete overload may be overlooked.

    That's all I got… and to be bitten, you would have to do that yet nothing else in the source file that would cause an "incomplete type" compiler error.

    EDIT: Following the lead of the other guys, I'd say the difficulty (may be considered danger) is ensuring that the forward declaration, in fact matches the real declaration. For functions and templates, argument lists have to be kept in sync.

    And you need to delete the forward declaration when removing the thing it declares, or it sits around and crufts up the namespace. But even in such cases, the compiler will point at it in the error messages if it gets in the way.

    The bigger danger is not having a forward declaration. A major disadvantage of nested classes is that they cannot be forward declared (well, they can inside the enclosing class scope, but that's only brief).

    0 讨论(0)
  • 2021-02-01 17:15

    Well, apart from the issues about duplication...

    ... there is at least one sore spot in the Standard.

    If you call delete on a pointer to an incomplete type, you get undefined behavior. In practice, the destructor may not get called.

    We can see that on LiveWorkSpace using the following command and sample:

    // -std=c++11 -Wall -W -pedantic -O2
    
    #include <iostream>
    
    struct ForwardDeclared;
    
    void throw_away(ForwardDeclared* fd) {
       delete fd;
    }
    
    struct ForwardDeclared {
       ~ForwardDeclared() {
          std::cout << "Hello, World!\n";
       }
    };
    
    int main() {
       ForwardDeclared* fd = new ForwardDeclared();
       throw_away(fd);
    }
    

    Diagnosis:

    Compilation finished with warnings:
     source.cpp: In function 'void throw_away(ForwardDeclared*)':
     source.cpp:6:11: warning: possible problem detected in invocation of delete operator: [enabled by default]
     source.cpp:5:6: warning: 'fd' has incomplete type [enabled by default] 
     source.cpp:3:8: warning: forward declaration of 'struct ForwardDeclared' [enabled by default]
     source.cpp:6:11: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined
    

    Don't you want to thank your compiler for warning you ;) ?

    0 讨论(0)
  • 2021-02-01 17:20

    Another danger of forward declarations is that it makes it easier to violate the One Definition Rule. Assuming that you have a.h forward declaring class B (which is supposed to be in b.h and b.cpp), but inside a.cpp you actually include b2.h which declares a different class B than b.h, then you get to undefined behaviour.

    0 讨论(0)
提交回复
热议问题