Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid unnecessary runtime overhead due to std::string "sink" parameters #50

Closed
vittorioromeo opened this issue Sep 23, 2015 · 5 comments
Assignees

Comments

@vittorioromeo
Copy link
Contributor

Most of the constructors in cpr take std::string parameters by const std::string&.

Digest(const std::string& username, const std::string& password);

This is not the most efficient way of dealing with "sink" parameters.
Refer to isocpp/CppCoreGuidelines's parameter passing diagram.

My suggestion is using perfect-forwarding, to always make sure sink std::string members are initialized as efficiently as possible. Example:

#define FWD(...) \
    ::std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)

template<typename TS0, typename TS1>
Digest(TS0&& username, TS1&& password) :
            Authentication{FWD(username), FWD(password)} {}
@whoshuu whoshuu added the Easy label Sep 23, 2015
@whoshuu
Copy link
Contributor

whoshuu commented Sep 23, 2015

Sounds good to me. Thanks for catching this!

To clarify for documentation purposes, the issue here is that the sink parameters will do a copy into each member parameter for the objects that have std::string members. Using a forwarding reference template parameter will copy lvalues (which is safe and correct) and move rvalues (which is efficient). This is similar to how the Session API has different methods for lvalue payload types and rvalue payload types.

whoshuu added a commit that referenced this issue Sep 23, 2015
whoshuu added a commit that referenced this issue Sep 23, 2015
Since c-style strings can't be moved from, and since the forwarding
references are greedy, a non-template constructor is necessary to
consume c-style string arguments
References #50
whoshuu added a commit that referenced this issue Sep 23, 2015
@vittorioromeo
Copy link
Contributor Author

Not sure what the issue is with forwarding c-style strings (as you said in e8e15c7) - could you elaborate?

I used perfect forwarding with std::string lvalues/rvalues and const char* and it seems to handle all the cases correctly. Coliru live example

@vittorioromeo
Copy link
Contributor Author

Also, I really think having a CPR_FWD(...) macro would make the code much easier to read (and much less error prone). Perfectly forwarding arguments is one of the places where I really think macros can shine.

#define CPR_FWD(...) \
    ::std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)

Note that:

template<typename T>
void something(T&& x)
{
    // All these are completely equivalent:
    something_else(std::forward<T>(x));
    something_else(std::forward<decltype(x)>(x));
    something_else(CPR_FWD(x));
}

// But the macro version is the one with least code repetition.
// And it's also the shortest one.

@whoshuu
Copy link
Contributor

whoshuu commented Sep 23, 2015

You're right about the c-style strings. I must've written the forwarding reference constructor wrong the first time and thought the issue was that I was passing c-style strings in the tests when it wouldn't build. This'll be fixed.

whoshuu added a commit that referenced this issue Sep 23, 2015
whoshuu added a commit that referenced this issue Sep 23, 2015
whoshuu added a commit that referenced this issue Sep 23, 2015
@whoshuu whoshuu self-assigned this Sep 24, 2015
whoshuu added a commit that referenced this issue Sep 24, 2015
whoshuu added a commit that referenced this issue Sep 24, 2015
whoshuu added a commit that referenced this issue Sep 24, 2015
whoshuu added a commit that referenced this issue Sep 24, 2015
@whoshuu whoshuu closed this as completed Sep 25, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants