When is it not a good idea to pass by reference?

后端 未结 9 2513
隐瞒了意图╮
隐瞒了意图╮ 2021-02-10 10:31

This is a memory allocation issue that I\'ve never really understood.

void unleashMonkeyFish()  
{  
    MonkeyFish * monkey_fish = new MonkeyFish();
    std::string          


        
9条回答
  •  别那么骄傲
    2021-02-10 10:33

    One way to do this is to have your string

    std::string name;
    

    As the data-member of your object. And then, in the unleashMonkeyFish function create a string like you did, and pass it by reference like you showed

    void setName( const std::string & parameter_name ) {
        name = parameter_name;
    }
    

    It will do what you want - creating one copy to copy the string into your data-member. It's not like it has to re-allocate a new buffer internally if you assign another string. Probably, assigning a new string just copies a few bytes. std::string has the capability to reserve bytes. So you can call "name.reserve(25);" in your constructor and it will likely not reallocate if you assign something smaller. (i have done tests, and it looks like GCC always reallocates if you assign from another std::string, but not if you assign from a c-string. They say they have a copy-on-write string, which would explain that behavior).

    The string you create in the unleashMonkeyFish function will automatically release its allocated resources. That's the key feature of those objects - they manage their own stuff. Classes have a destructor that they use to free allocated resources once objects die, std::string has too. In my opinion, you should not worry about having that std::string local in the function. It will not do anything noticeable to your performance anyway most likely. Some std::string implementations (msvc++ afaik) have a small-buffer optimization: For up to some small limit, they keep characters in an embedded buffer instead of allocating from the heap.

    Edit:

    As it turns out, there is a better way to do this for classes that have an efficient swap implementation (constant time):

    void setName(std::string parameter_name) {
        name.swap(parameter_name);
    }
    

    The reason that this is better, is that now the caller knows that the argument is being copied. Return value optimization and similar optimizations can now be applied easily by the compiler. Consider this case, for example

    obj.setName("Mr. " + things.getName());
    

    If you had the setName take a reference, then the temporary created in the argument would be bound to that reference, and within setName it would be copied, and after it returns, the temporary would be destroyed - which was a throw-away product anyway. This is only suboptimal, because the temporary itself could have been used, instead of its copy. Having the parameter not a reference will make the caller see that the argument is being copied anyway, and make the optimizer's job much more easy - because it wouldn't have to inline the call to see that the argument is copied anyway.

    For further explanation, read the excellent article BoostCon09/Rvalue-References

提交回复
热议问题