0

I have the following compare method. The method compare and return diff result.

I want to minimize the times that the result list is copied (to temporal and to assignment).

One way to do this is to add additional reference argument for the result, but i love that utils function are closed (they dont change values), so i prefer to avoid this.

One copy can be avoid by using the const& in the assignment

const& list<uint32> diff = getDiffNewElements (...)

, can be a way to also avoid the local copy to temporal ?

The diff method:

list<uint32> getDiffNewElements(const list<Row>& src ,const list<Row>& dst) {
    list<uint32> result;

        ... Do Some compare

        return result;
}
4

2 回答 2

2

There are potentially two copies in the code that you present. One inside the function, from the variable result to the returned object. NRVO will take care of that if the complexity of the function allows for it. If as it seems, you have a single return statement, then the compiler will elide that copy (assuming that you are not disabling it with compiler flags and that you have some optimization level enabled).

The second potential copy is in the caller, from the returned value to the final storage. That copy is almost always elided by the compiler, and it is even simpler to do here than in the NRVO case: the calling convention (all calling conventions I know of) determines that the caller reserves the space for the returned object, and that it passes a hidden pointer to that location to the function. The function in turn uses that pointer as the destination of the first copy.

A function T f() is transformed into void f( uninitialized<T>* __ret ) (there is no such thing as uninitialized<>, but bear with me) and the implementation of the function uses that pointer as the destination when copying in the return statement. On the caller site, if you have T a = f(); the compiler will transform it into T a/*no construction here*/; f(&a);

There is an interesting bit of code in the question that seems to indicate that you have been mislead in the past: const list<uint32>& diff = getDiffNewElements(...). Using a reference rather than storing the value directly (as in list<uint32> diff = getDiffNewElements(...)) has no impact at all in the number of copies that are made. The getDiffNewElements still needs to copy (or elide the copy) to the returned object and that object lives in the scope of the caller. By taking a const reference you are telling the compiler that you don't want to directly name that object, but rather keep it as an unnamed object in the scope and that you only want to use a reference to it. Semantically it can be transformed into:

T __unnamed = getDiffNewElements(...);  // this copy can be elided
T const& diff = __unnamed;

The compiler is free, and will probably, optimize the reference away, using the identifier diff as an alias to __unnamed without requiring extra space, so in general it will not be worse than the alternative, but the code is slightly more complex and there is no advantage at all.

Long time ago, when I had time, I started a blog and wrote a couple of articles on value semantics, (N)RVO and copy elision. You might want to take a look.

于 2012-11-01T12:02:06.267 回答
0

You are looking in the wrong direction. Your getDiffNewElements method does not create unnecessary copies, because modern compilers do RVO (which was pointed in the comments, although if your compiler doesn't do RVO, there is nothing you can do about it, your const& won't help). The way you can optimize this function is to return vector instead of list, since you can call reserve on vector and avoid memory allocations every time you push_back a new element. list does not preallocate memory with default allocator and it has no reserve method to do that.

于 2012-11-01T11:18:57.647 回答