Prevent member variable from being modified after construction

This is a discussion on Prevent member variable from being modified after construction within the C++ Programming forums, part of the General Programming Boards category; I've ran into situations once or twice where the class constructor sets a member variable, after which it should not ...

  1. #1
    Registered User
    Join Date
    May 2003
    Posts
    82

    Prevent member variable from being modified after construction

    I've ran into situations once or twice where the class constructor sets a member variable, after which it should not be modified.

    Is there a way of getting a member to behave as if it were const, but only after the constructor runs?

    Some example code:
    Code:
    class Foo {
        public:
        Foo(int in) {
            member = in;    // initial assignment in constructor is legal
        };
        
        void testMember() {
            if(member = 1);    // accidental assignment should be illegal
               //do something
            
            // legitimately modify other class data besides member
        };    
        
        private:
        int member; // should not be modified by any function besides constructor
    };
    The code executes. I'm just curious if there is someway to make the accidential reassignment in testMember() illegal.

    Thanks.
    Last edited by AH_Tze; 12-11-2004 at 02:45 PM.

  2. #2
    Super Moderator
    Join Date
    Sep 2001
    Posts
    4,913
    You could have everything private, and modifiable only by the use of member functions (I think that's called properties...). Have these functions check for a flag set when the constructor runs before altering the variable.

  3. #3
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,796
    >Is there a way of getting a member to behave as if it were const, but only after the constructor runs?
    Make it const.
    Code:
    class Foo {
    public:
      Foo(int in): member(in) {
      }
    
      void testMember() {
        if(member = 1) // Illegal
          ;
      }   
    
    private:
      const int member;
    };
    Because the constructor initializer list can initialize const members, you can use it to perform the initialization while still benefitting from the member being const.
    My best code is written with the delete key.

  4. #4
    Super Moderator
    Join Date
    Sep 2001
    Posts
    4,913
    Make it const.
    Or that . It just seemed to obvious!

  5. #5
    Registered User
    Join Date
    May 2003
    Posts
    82
    Code:
    Foo(int in): member(in) {
    }
    Ah. It works. But could you explain that syntax?

    I had tried:
    Code:
    Foo(int in) {
          member = in; 
    };
    and gotten an "illegal assignment of read-only data member" from dev-c++.

    I don't understand the difference between the two.

  6. #6
    Registered User
    Join Date
    Dec 2004
    Location
    UK
    Posts
    109
    Quote Originally Posted by AH_Tze
    Code:
    Foo(int in): member(in) {
    }
    Ah. It works. But could you explain that syntax?

    I had tried:
    Code:
    Foo(int in) {
          member = in; 
    };
    and gotten an "illegal assignment of read-only data member" from dev-c++.

    I don't understand the difference between the two.
    In the first syntax the variable is initalised as it constucted. In the second the variable is initialised after it is constructed which is illegal since the variable is const.

  7. #7
    Registered User
    Join Date
    May 2003
    Posts
    82
    Ah. I'd seen something similiar using user-defined types, but I'd never seen a primitive data type being initialized that way. Very clever.

    Thanks all, and I am once again in Preludes debt.

  8. #8
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,796
    >but I'd never seen a primitive data type being initialized that way. Very clever.
    I would recommend getting into the habit of using the initialization list rather than assignment in your constructors. It's always legal, and often more efficient. Of course, it could be impractical if you have a huge number of members to initialize, but that's really a sign of bad design IMO.
    My best code is written with the delete key.

  9. #9
    Registered User
    Join Date
    Jun 2004
    Posts
    722
    Quote Originally Posted by AH_Tze
    Code:
    Foo(int in): member(in) {
    }
    Ah. It works. But could you explain that syntax?

    I had tried:
    Code:
    Foo(int in) {
          member = in; 
    };
    and gotten an "illegal assignment of read-only data member" from dev-c++.

    I don't understand the difference between the two.
    Imagine that member is ... a vector, and you want it to have at first 10 elements allocated. Calling
    Code:
    Foo(int in) {
          member = vector<int>(10); 
    };
    isn't the same as
    Code:
    Foo(int in) : member(10){}
    Why you may ask?
    When as class is declared, memory is allocated. If the class is derived, the base class constructor is called. The variables constructors are called, and last the main constructor for that class. This behaviour is extremely important because when the body of a contructor is executed, every variable must have been correctly initialized, otherwize, manipulating those variable could result fatal. Making an assignement to a int in the body isn't bad practice, but it's not also good, because it can lead to bad habits.
    But making an assignement to a vector class is very bad!!! Because when your constructor is executed your vector class is already constructed. Assingning it another value through '=' implies creating a new temporary vector, calling operator=(), then deconstructing the temporary vector. This is EXTREMELY ineficient.

    EDIT: here's an example of this behaviour
    Code:
    #include <iostream>
    
    class A{
    	int val;
    public:
    	A(int n=0) : val(n){std::cout  << "A   constructed and val "<<val<<std::endl;}
    	~A(){std::cout  << "A deconstructed and val "<<val<<std::endl;}
    	A& operator=(const A& a){
    		val=a.val;
    		std::cout  << "A   operator=() called and val "<<val<<std::endl;
    	return *this;}
    };
    class B{
    	int val;
    public:
    	B(int n=1) : val(n){std::cout  << "B   constructed and val "<<val<<std::endl;}
    	~B(){std::cout  << "B deconstructed and val "<<val<<std::endl;}
    };
    class C{
    	int val;
    public:
    	C(int n=2) : val(n){std::cout  << "C   constructed and val "<<val<<std::endl;}
    	~C(){std::cout  << "C deconstructed and val "<<val<<std::endl;}
    
    };
    class D: public C{
    public:
    	A a;
    	B b;
    	D(){
    		std::cout  << "D   constructed\n";
    		a = A(10);
    		b = B(56);
    
    	}
    	~D(){std::cout  << "D deconstructed"<<std::endl;}
    };
    int main(){
    	D d;
    	return 0;
    }
    And the output
    Code:
    //beginning - D class initialization
    C   constructed and val 2    //base C class of D constructed
    A   constructed and val 0    //class A var in D constructed
    B   constructed and val 1    //class B var in D constructed
    D   constructed                   //D constuctor executed
    A   constructed and val 10  //temporary A class for assignement created
    A   operator=() called and val 10   //a assigned
    A deconstructed and val 10 //temporary var desconstructed
    B   constructed and val 56  //temporary B class for assignement 
    B deconstructed and val 56 //temporary B class deconstructed
    // - My compiler seemed to create a default B::operator=()
    //I dont' know if this is standard behaviour
    
    //end
    D deconstructed
    B deconstructed and val 56
    A deconstructed and val 10
    C deconstructed and val 2
    If you call the constructors for the variables, recomended, instead of assigning values to then, like showed above, the output would be
    Code:
    C   constructed and val 2
    A   constructed and val 10
    B   constructed and val 56
    D   constructed
    
    D deconstructed
    B deconstructed and val 56
    A deconstructed and val 10
    C deconstructed and val 2
    Each constructor called only once. Good behaviour
    Last edited by xErath; 12-11-2004 at 04:00 PM.

  10. #10
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    In the second the variable is initialised after it is constructed which is illegal since the variable is const.
    Actually in the second one the very is left uninitialized and it attempts to assign a value to a const object.

    Remember initalization is done once and only once at creation. Everything after that point is assignment.

    edit: @AH_Tze: If you want to make sure that none of your data members are changed by a particular member function you can declare that function const. Example:
    Code:
    class Foo
    {
      int x;
      const iny y;
      public:
        Foo(int i) : x(1), y(i) {}
        int getX() const { return x; }
        int getY() const { return y; }
        int changeY(int i) { return y=i; } // error y is const
        int changeX(int i) const { return x=i; } // error function is const
    };
    By putting const after the () you ensure that nothing is changed in the object regardless of constness
    Last edited by Thantos; 12-11-2004 at 03:44 PM.

  11. #11
    Toaster Zach L.'s Avatar
    Join Date
    Aug 2001
    Posts
    2,686
    By putting const after the () you ensure that nothing is changed in the object regardless of constness
    The exception being of course mutable variables.

    Another note about intializer list:
    - If you are constructing an object of a derived type, and need to pass data down to the constructor of the base type, this is the only place to do it.
    - If you have member data (of user defined types) which do not have default constructors, then they must be initialized at construction via the initializer list.
    The word rap as it applies to music is the result of a peculiar phonological rule which has stripped the word of its initial voiceless velar stop.

  12. #12
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    Yeah I forgot about mutable mainly because I've never seen it's usage. I should point out that const is just a compiler guarantee and the clever (or very unlucky) programmer can easily get around it.

  13. #13
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,796
    >>Actually in the second one <snip detailed explanation>
    >The exception being of course mutable variables.
    Does this ever seem to anyone like a geek's ........ing contest?

    Geek 1: "I'm smart. Here's why."
    Geek 2: "You're smart, but there's a miniscule error here. So I'm smarter."
    Geek 3: "You're smart too, but not smarter than me because your correction makes an assumption."
    Geek 4: "You're the smartest one of all because you knew that, but I'm even smarter because I know that in the Real World(TM), you can't do anything serious without making assumptions."
    Geek 1: (defending his honor) "The question was theoretical to begin with, so you're all not as smart as me because I answered it with that in mind. MUAHAHAHAHAHA!"

    * Thread degenerates into flames about trivial mistakes in grammar and spelling *

    My best code is written with the delete key.

  14. #14
    Super Moderator
    Join Date
    Sep 2001
    Posts
    4,913
    Some greek philosopher used a similar argument. I think it was Plato:

    Geek #5: "I must be the smartest one here because I'm the only one that knows I don't know everything!"
    Geek #6: "Your fly's open."

  15. #15
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    Geeks arguements are still better then nerds arguring about Sci Fi TV shows

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 09:18 PM
  2. pointers
    By InvariantLoop in forum C Programming
    Replies: 13
    Last Post: 02-04-2005, 09:32 AM
  3. Outputting to a File Modified Text
    By alpha in forum C++ Programming
    Replies: 8
    Last Post: 11-24-2003, 08:39 PM
  4. Replies: 3
    Last Post: 10-10-2002, 08:34 AM
  5. Using 'if' with char arrays or string objects
    By c++_n00b in forum C++ Programming
    Replies: 36
    Last Post: 06-06-2002, 10:04 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21