CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 14 of 14
  1. #1
    Join Date
    Mar 2010
    Posts
    71

    Help - how to initialize reference variable?

    Hi,

    This is an urgent issue so your help would be highly appreciated.

    The following code is extracted from a real project.

    Code:
    #include <iostream>
    using namespace std;
    
    class B
    {
      public:
        B(const int &n) : i(n)
        {
          cout << "In B constructor" << endl;
        }
    
      private:
        int &i;
    };
    
    int main()
    {
      int i = 28;
      B b(i);
    
      return 0;
    }
    In this code snap, B::i must be a reference and B's constructor must take "const int &n". When building this code, I got compile error:

    const_constructor.cpp: In constructor 'B::B(const int&)':
    const_constructor.cpp:8: error: invalid initialization of reference of type 'int&' from expression of type 'const int'

    Could someone please tell me how I fix this compile error?

    Thanks,
    BJT
    Last edited by BJT; September 15th, 2010 at 10:21 AM.

  2. #2
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Help - how to initialize reference variable?

    You either need to drop the const qualifier on the constructor argument, or else add one to the member i. You can't go from a const reference to a non-const reference without a cast (and you shouldn't use a cast unless you're positive one is necessary).

    You should be aware either way that the class B will not be able to auto-generate a copy constructor since it has a reference member. You should therefore either write one yourself, or else make B explicitly uncopyable by declaring the cctor and operator= as private. Alternatively, if you store i as an (unowned) pointer rather than a reference, then the copying problem goes away.

  3. #3
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: Help - how to initialize reference variable?

    Quote Originally Posted by Lindley
    You should be aware either way that the class B will not be able to auto-generate a copy constructor since it has a reference member.
    I think that the copy constructor can be implicitly defined even with a reference member. It is the copy assignment operator that has a problem here, but we normally either implement or disable the both of them together.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  4. #4
    Join Date
    Apr 2004
    Location
    Canada
    Posts
    1,342

    Re: Help - how to initialize reference variable?

    Quote Originally Posted by Lindley View Post
    You should be aware either way that the class B will not be able to auto-generate a copy constructor since it has a reference member. You should therefore either write one yourself, or else make B explicitly uncopyable by declaring the cctor and operator= as private. Alternatively, if you store i as an (unowned) pointer rather than a reference, then the copying problem goes away.
    Really? In my experience, the compiler can still auto-generate a copy constructor, since references can be copy-constructed. It is only the assignment operator that the compiler cannot generate.

    EDIT: laserlight beat me to it.
    Last edited by HighCommander4; September 15th, 2010 at 04:40 PM.
    Old Unix programmers never die, they just mv to /dev/null

  5. #5
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Help - how to initialize reference variable?

    You're both correct, I misspoke. Same caveats apply though.

  6. #6
    Join Date
    Mar 2010
    Posts
    71

    Re: Help - how to initialize reference variable?

    After add "const" to B::i, then the code posted ABOVE can be compiled but it does not fix the actual problem in the real project.

    (1) Class B in real project is a base class. Derived classes pass a const variable to the base class B. So it's better to keey the incoming parameter as const. Otherwise, all derived class need to be changed to pass a non-const parameter.

    (2) Class B has a member function setN(const int &n). It's added to the following code. When compile the code, I got another error:

    const_constructor.cpp: In member function 'void B::setN(const int&)':
    const_constructor.cpp:22: error: assignment of read-only location

    I think this is caused by adding "const" to B::i

    Is it possible to keep const in B's constructor and let setN() to change B::i in run time?

    Code:
    #include <iostream>
    using namespace std;
    
    class B
    {
      public:
        B(const int &n) : i(n)
        {
          cout << "In B constructor" << endl;
        }
    
        void setN(const int &n);
    
      private:
        const int &i;
    };
    
    void B::setN(const int &n)
    {
        i = n;
    }
    
    int main()
    {
      int i = 28;
      B b(i);
    
      b.setN(i);
    
      return 0;
    }
    Last edited by BJT; September 15th, 2010 at 11:30 AM.

  7. #7
    Join Date
    Mar 2010
    Posts
    71

    Re: Help - how to initialize reference variable?

    Any suggestion would be appreciated.

    Thanks,
    BJT

  8. #8
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Help - how to initialize reference variable?

    Quote Originally Posted by BJT View Post
    Derived classes pass a const variable to the base class B.
    The key question in my mind is why they're doing this. Could you give an example?

    If the goal of setN() is to update the value indicated by the reference, and that value corresponds to some member of a derived class, then why not make setN() virtual and let the derived classes override it?

  9. #9
    Join Date
    Oct 2009
    Posts
    577

    Smile Re: Help - how to initialize reference variable?

    I used reference members only one or two times within 18 years C++. Actually I couldn't think a good reason why that is necessary, especially if a user of a derived class must provide the referenced variable. It doesn't seem to be a good design and probably offends encapsulation principle. How will you prevent those users from providing a local variable which goes out-of-scope like in the code below?

    Code:
    D* X::f()
    {
         int i = 100;
         return new D(&i);
    }   // kaboom
    I remember when I once used a reference member I provided the referenced variable myself:

    Code:
    class X
    {
          Y & y;
    public:
          X() : y(*(new Y(0)))  {}
          X(int i) : y(*(new Y(i)))  {}
          X(const X& x) : y(*(new Y(x.y)))  {}
    
          virtual ~X() { delete &y; }
    };
    There was a reason why I used a reference member and not a pointer member but I didn't know what was the case anymore. The difference to your code is that the reference was managed by the class itself and that there is no way to spoil the reference address from outside, not even from derived classes.

  10. #10
    Join Date
    Mar 2010
    Posts
    71

    Re: Help - how to initialize reference variable?

    Quote Originally Posted by Lindley View Post
    The key question in my mind is why they're doing this. Could you give an example?

    If the goal of setN() is to update the value indicated by the reference, and that value corresponds to some member of a derived class, then why not make setN() virtual and let the derived classes override it?
    This is a very good question that forces me to go back and check the original code in more details. The project class structure looks like Dn -> ... -> D2 -> D1 -> B (base class). Several properties are distributed (initialized) to different classes via their constructors based on the nature of these properties.

    Not very sure about the reason why "const int &i", instead of "const int i", is used in class B but variable "&i" or "i" should indeed be in class B. "const int &i" used to be initialized in constructor, and then stay unchanged. Now for some reason we need to change the value of the variable pointed by &i after it's initialized. That's why setN() is introduced.

    To keep using &i at least for now, the code snap is changed to the following one by using const_cast. Does it look okay, or does it have any potential issues?

    Code:
    #include <iostream>
    using namespace std;
    
    class B
    {
      public:
        B(const int &n) : i(*const_cast<int*>(&n))
        {
          cout << "In B constructor" << endl;
        }
    
        void setN(const int &n);
    
      private:
        int &i;
    };
    
    void B::setN(const int &n)
    {
        i = n;
    }
    
    int main()
    {
      int i = 28;
      B b(i);
    
      b.setN(i);
    
      return 0;
    }
    Thanks,
    BJT

  11. #11
    Join Date
    Mar 2010
    Posts
    71

    Re: Help - how to initialize reference variable?

    Quote Originally Posted by itsmeandnobodyelse View Post
    ... Actually I couldn't think a good reason why that is necessary, especially if a user of a derived class must provide the referenced variable. It doesn't seem to be a good design and probably offends encapsulation principle. How will you prevent those users from providing a local variable which goes out-of-scope like in the code below?
    Yes, agree. I don't see a good reason why it's necessary either. Maybe it was designed that way originally for supporting something, and later that "something" was removed but the reference was not changed accordingly.

  12. #12
    Join Date
    Oct 2009
    Posts
    577

    Smile Re: Help - how to initialize reference variable?

    Quote Originally Posted by BJT View Post
    This is a very good question that forces me to go back and check the original code in more details. The project class structure looks like Dn -> ... -> D2 -> D1 -> B (base class). Several properties are distributed (initialized) to different classes via their constructors based on the nature of these properties.

    Not very sure about the reason why "const int &i", instead of "const int i", is used in class B but variable "&i" or "i" should indeed be in class B. "const int &i" used to be initialized in constructor, and then stay unchanged. Now for some reason we need to change the value of the variable pointed by &i after it's initialized. That's why setN() is introduced.

    To keep using &i at least for now, the code snap is changed to the following one by using const_cast. Does it look okay, or does it have any potential issues?
    Using a reference member - same as with a pointer member - has the advantage that the member can be in shared memory or be a global variable so that it may be initialized differently and to a time where no instance of the class B already exists. The same you normally can only do with static class members but which are singletons then. To find out whether you could change it to non-reference you would need to check each single input variable for the i member of baseclass B and find out where they take the integer from and how (and to what time) that integer was initialized. You also would need to find out if there was any const_cast (or C cast) on those variables after the class instance of B (or derived class) was constructed.

    For the implementation I would let it a const int and do the cast in the SetN. So your change only is in the new function and doesn't reflect old code.

    Code:
    #include <iostream>
    using namespace std;
    
    class B
    {
      public:
        B(const int &n) : i(n)
        {
          cout << "In B constructor" << endl;
        }
    
        void setN(int n);
    
      private:
        const int & i;
    };
    
    void B::setN(int n)
    {
        int * pi = const_cast<int*>(&i);
        *pi = n;
    }
    
    int main()
    {
      const int i = 28;
      B b(i);
    
      b.setN(i);
    
      return 0;
    }
    Last edited by itsmeandnobodyelse; September 16th, 2010 at 05:44 AM.

  13. #13
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Help - how to initialize reference variable?

    I wouldn't bother with a reference member, it is just too restricting. You can get the exact same behavior with a member pointer, without all that hassle.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  14. #14
    Join Date
    Mar 2010
    Posts
    71

    Smile Thanks everyone for your valuable information and help!

    Thanks everyone for your valuable information and help!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured