Re: [Cppunit-devel] returning const reference (was: CppUnit 1.8.0 features...)
Brought to you by:
blep
From: Baptiste L. <gai...@fr...> - 2001-09-26 14:16:00
|
Quoting Noel Llopis <ll...@ho...>: > First time contributing to the list, but here it goes... Well, look like you hit "reply" instead of "reply all" (happen to me sometime too)... Your welcome to contribute to the list. While I found some bit of interest discussing the current topic, I would be more interested on having feedback on CppUnit design (Exception, TestFailure & co...) ;-) > > > I personally disagree with lots of these comments, as do lots of > other > > people, whose comments you can see if you follow some of the links > > from these Wiki pages (see UseConstMemberFunctions and > ConstCorrectness). > > Absolutely. I think doing that would be a big step backward I don't know if you read all the thread. CppUnit won't change in those aspect. I was just stating that CppUnit should not enforce users to respect the constness policy with their objects. [...] > I don't buy the idea that const gets in the way of refactoring. > That's right up there with saying that most functions should be > public or virtual. > > const, if anything, helps refactoring by reminding you of the > itention of the code. Isn't XP so big on self documenting code? > What better example than the compiler yelling at you because > you tried to modify something when somebody explicitely > decided that it shouldn't? If you're going to change something > as fundamental as that, you might as well remove a couple of > const statements. That's because you use const to define an "immutable" interface to your objects. I prefer to stick to pass by value, or other interface that don't provide "write" access... And you exactly stated why it may be hard to change: "somebody explicitely say that it shouldn't". Yeah, but now I need to. Accessing mutable method is my change. How hard can that be ? Find all the callers, change the reference/pointer type. Might also have to search their callers, and so on... Of course, that time "lost" making that change have to be compared to the time that the compiler would save for you. I find myself doing quite well without that belt... And not having to think about "should I pass/use a const pointer or a mutable pointer" make think easier. > > My guess is that it depends on the way your style of code. All I > > know is that I have applyied those rules (my version) in my > > development for the last 3 months (including a new project at work), > > and found it to work pretty well. > > Of course, it's all a personal preference. Some people also > like to limit themselves to the C subset when they're using C++. > I found that correctly using const (for references and member functions) > has been extremely useful for me at work and in my own code. Yup. It has to do with convention. I found those I defined to be working quite well for me. They still need some rafinment, and will evolve as everyhing does. [...] > > > >> 2) prefer pass-by-value to const reference > > > >> => don't need to had "const" method to object. > > Why would you ever want to do that? Const references have > to be the cleanest, most efficient way of passing parameters. > Why would you want to copy the whole object, so you > can modify it inside the function? If so you can always make > a local copy (although I suspect that it could be done in > a different, much more clear and efficient way). With my conventions, references are pointers and allow polymorphism. My conventions are that pointers are used for reference objects, and pass by value is used for value objects. Const references may be added in optimization phase when need to pass value object. Since most of the object I have are not value object, I mostly use pointers around (by the way, I forgot another of my rule: public methods should never return NULL pointer (the null flag bug pattern)). > > > >> 3) avoid to return const reference, prefer return by value > > > >> => the former make it difficult to change the implementation > > > > > > Not sure I agree with that. I think it probably varies by class. > > My experience is that if you have: > > const std::vector<Test*> &getTests() > > > > You can not change your implementation to something else ( > > std::map<string,Test*> for example) without impacting client. But if > you had: > > std::vector<Test*> getTests(), > > then it could easily be done. > > I don't see how that makes it any easier to update. It seems > that in both cases you need to update the type of the variable that > will receive the return value. No. If you return a vector by value, and you store the data in a map, then you can create a temporary vector that you return: sdt::vector<Test*> getTests() { std::vector<Test*> tests; for ( iterates the map ) tests.push_back(...) return tests; } > I usually follow the rule to return a const reference when possible, > and a value otherwise. The nice thing abou this is that you can > switch between the two without having to update the client code > at all. > > So const MyClass & a = something.GetA(); > will work both when a is returned by value or const reference. Beware of the "you can switch between the two at will". While the reference on a temporary is suposed to remain valid as long as the reference exist, you can run in some troubles. For example, return by value returns a mutable object ( myObject.setName( file.readLine().stripSpaces(), which is not possible with const reference ). Here is an example of unwanted behavior: (note that while it can be spoted easily there, the actual "obj.set" can occur after a long serie of method calls that would finaly call back on obj) --- #include <iostream> #include <vector> class Object { public: // std::vector<int> get() // for the correct version const std::vector<int> &get() { return _values;} void set( const std::vector<int> &values ) { _values = values; } private: std::vector<int> _values; }; void main() { Object obj; const std::vector<int> &values = obj.get(); std::vector<int> otherValues( values ); otherValues.push_back( 3 ); // change the value in obj, with const ref&, indirectly change values! obj.set( otherValues ); Object obj2; obj2.set( values ); std::cout << "obj.get() : " << obj.get().size() << std::endl << "obj2.get() : " << obj2.get().size() << std::endl; } -- and you get: obj.get() : 1 obj2.get() : 1 instead of: obj.get() : 1 obj2.get() : 0 --- Also, another source of trouble would be: const std::vector<int> &values = obj->get(); delete obj; Amazingly, values is still a valid reference. As before, the delete can occurs far away (A less likely case, I concede). So my take is that pass-by-value provide stronger isolation, and therefore make refactoring somewhat easier. Baptiste. > --Noel > ll...@ho... > > --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |