1

pretty specific question here!

I have a class which holds data about a planet. For example, it has things like a vector (double x, double y, double z) to hold its position, and a double variable to hold its radius.

I often use references to get a "read only public access" to the private variables. I call a setter method to change the private variable.

However, I don't think this is allowed inside a dynamic container such as a vector or list.

I have tried "constant constant" pointers, with the idea being once initialized in an initialization list, they will not be able to point to anything else or modify the variable. But the same error message appears at compile time.

The message is this: "error: non-static const member const double* const x, can't use default assignment operator"

So, there is a problem with copying the class when I do a "push_back" on to a vector - right?

Here is an example code:

class planet{

    private:

        double _radius;

    public:

        // Constructor
        planet() : rad(_radius){
           _radius = 0.0f;
        }

        // This is a setter method - works fine
        void setrad(double new_rad){
            _radius = rad;
        }

        // This is a better solution to the getter method
        // - does not seem to work with dynamic containers!
        const double& rad; // This is initialized in the constructor list
};

int main(...){

...

    std::vector<planet> the_planets;
    planet next_planet_to_push;
    next_planet_to_push.setrad(1.0f);

    // This causes the error!
    the_planets.push_back(next_planet_to_add);

...

}
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • What is the problem with giving read only access via getter methods? I see no reason to store references here. – juanchopanza Sep 03 '12 at 10:04
  • You need to define a copy-constructor & assignment operator for your Planet class. Try planet a; planet b; a = b; – mythagel Sep 03 '12 at 10:04
  • I'm not sure why you feel that a reference is "better" than an access function, but it increases the object size and the runtime cost of access, and (as you've found) prevents the class from being trivially copyable. An access function should be inlined, in which case there should be no overhead compared with direct access to the member. – Mike Seymour Sep 03 '12 at 11:46
  • Ah yes I have just researched inline functions, this could be a good solution, thanks. :) – FreelanceConsultant Sep 03 '12 at 14:16

4 Answers4

1

You'll need to provide your own copy constructor and assignment operator for classes that contain member references or const members (in your case, both).

The compiler-generated ones will attempt to do a shallow copy which is not possible in this case.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
1

std::vector requires operator= in order to work. Default operator= just assigns each member. It can't be done for const &

Andrew
  • 24,218
  • 13
  • 61
  • 90
  • Can you point me in the direction on how to do this? What should I google for? Thanks! – FreelanceConsultant Sep 03 '12 at 10:18
  • @EdwardBird: i would do the same thing Kerrek SB recommends - use a simple getter – Andrew Sep 03 '12 at 10:20
  • 1
    @EdwardBird: there is an option to use pointer instead of a references because a pointer can be rebind. But it's ugly. Don't do you it - use a simple getter – Andrew Sep 03 '12 at 10:23
  • I tried a: const double* const rad; and then tried initializing it in an initialization list with my own basic constructor. Same error message! What am I doing wrong? – FreelanceConsultant Sep 03 '12 at 10:29
  • 1
    @EdwardBird: you can't change a const pointer. You can change a pointer to const. But please, don't do that. Provide a getter – Andrew Sep 03 '12 at 10:54
  • Yes of course, it would be silly... That pointer could point ANYWHERE! I think I can use my own defined copy and assignment operators to make it work though... Is that possible? – FreelanceConsultant Sep 03 '12 at 14:13
  • @EdwardBird: I don't see a way to do so because you will need to rebind the reference – Andrew Sep 03 '12 at 14:20
  • Yes, but I can use const double& rad without binding it until the constructor is called. There must surely be a way of getting it to work with my own copy and assignment operators to be used when one instance of the class is "pushed_back" onto the stack? Or perhaps there just is not any way of doing that? :( – FreelanceConsultant Sep 03 '12 at 14:36
1

Indeed, elements of a std::vector must be assignable, so they can't contain const or reference members.

But why not have a simple accessor function:

double rad() const { return _radius; }
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • The answer is simple, the above solution is long to type, and it is much more intuitive to be able to type if(planet.x > 10) ... although I agree it is not good to be able to write to the variable in this way – FreelanceConsultant Sep 03 '12 at 10:14
  • Two extra parentheses are too long to type? Well, you could have an `std::reference_wrapper` member if you must. – Kerrek SB Sep 03 '12 at 10:28
  • No, not too long, just not intuitive! :) I will google std::reference_wrapper now. – FreelanceConsultant Sep 03 '12 at 10:35
  • @EdwardBird: Which one is more intuitive: the steering wheel of a car, or the rudder of a boat? – Kerrek SB Sep 03 '12 at 10:37
  • Come on, you cannot deny that using my.height is more intuitive than my.height()?! Who wants to call a method? Why not just grab the (readonly) variable! But since you ask the question, the steering wheel is more intuitive. ;) – FreelanceConsultant Sep 03 '12 at 10:43
  • 3
    @EdwardBird I deny it: `my.height` is not more intuitive than `my.height()`. There. – juanchopanza Sep 03 '12 at 11:55
  • 1
    @juanchopanza: Especially since we already have `myStr.length()`, `myGadget.size()` and `myEncoding.width()`! :-) – Kerrek SB Sep 03 '12 at 12:07
  • mm I see your point... might just use an inline getter... it seems to be the easiest solution... – FreelanceConsultant Sep 03 '12 at 14:18
0

What is even the problem with just making the radius public?

If all the setter does is this->radius = some_other_radius, the code provides no benefit: is adding code that provides features that the language already provides worth it?

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510