views:

142

answers:

1
#include <iostream>
#include <assert.h>

using namespace std;

struct Base
{
  Base() : m_member1(1) {}

  Base(const Base & other) 
  { 
    assert(this != &other);   // this should trigger
    m_member1 = other.m_member1; 
  }

  int m_member1;
};

struct Derived
{
  Derived(Base & base) : m_base(m_base) {} // m_base(base)

  Base & m_base;
};

void main()
{
  Base base;

  Derived derived(base);

  cout << derived.m_base.m_member1 << endl; // crashes here
}

The above example is a synthesized version of a mistyped constructor. I used reference at the class member Derived::m_base because I wanted to make sure that the member will be initialized as the constructor had called. One problem is that nor GCC nor MSVC gives me a warning at m_base(m_base). But the more serious for me is that the assert finds everything fine and the application crashes later (sometimes far away from the mistake). Question: Is there any way to indicate such mistakes?

+3  A: 

The assert doesn't trigger because you're not creating an instance of Base in the call m_base(m_base). This is just initializing the reference Base& m_base. If you actually want to call the copy constructor, then declare m_base as a value Base m_base.

Also, one way to catch that kind of mistake is to have your compiler warn about unused parameters. The gcc flag is -Wunused-parameter, or -Wextra -Wunused.

Jesse Beder
normally A gives me the mentioned compiler warning. But in the example this warning does not come. The answer is correct about the lack of calling the copy constructor. But my problem is the dangling reference.
psaghelyi
Jesse Beder
Here's a bug report discussing self-initialization (`int i = i`): http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34772. But it seems to focus on warning when you use the variable, not when you initialize it with itself, which seems like where it *should* be warning you.
Jesse Beder
I can imagine a scenario when self-initialization should be OK. Maybe someone wants to call the operator= for some reason in this weird way. But a reference should always refers to somewhere with size. (At least as long as the referred object is not deleted)
psaghelyi