Will (N)RVO be applied with my function in this situation? - c++

I have the following code: (ok, in reality it's much more complicated, but I simplified it to make it easier to understand. so please disregard the things that seems stupid. I can't change them in my real situation)
#include <string>
using std::string;
ReportManager g_report_generator;
struct ReportManager
{
// I know, using c_str in this case is stupid.
// but just assume that it has to be this way
string GenerateReport() { string report("test"); return report.c_str(); }
}
string DoIt(bool remove_all)
{
if(g_report_generator.isEmpty())
return string();
string val = g_report_generator.GenerateReport();
if(remove_all)
g_report_generator.clear();
return val;
}
void main()
{
string s = DoIt(true);
}
Will (N)RVO be applied with my functions?
I did a bit of research, and it would seem like it, but I'm not really convinced and I'd like a second opinion (or more).
I'm using Visual Studio 2017.

To solve your problem I rewrote it.
#include <string>
struct string : std::string {
using std::string::string;
string(string&& s) {
exit(-1);
}
string(string const&) {
exit(-2);
}
string() {}
};
struct ReportManager
{
// I know, using c_str in this case is stupid.
// but just assume that it has to be this way
string GenerateReport()
{
string report("test");
return report.c_str();
}
bool isEmpty() const { return true; }
void clear() const {}
};
ReportManager g_report_generator;
string DoIt(bool remove_all)
{
if(g_report_generator.isEmpty())
return string();
string val = g_report_generator.GenerateReport();
if(remove_all)
g_report_generator.clear();
return val;
}
int main()
{
string s = DoIt(true);
}
The trick with this rewriting is that elision permits skipping copy/move ctors. So every time we actually copy an object (even if inlined), we'll insert an exit clause; only by elision can we avoid it.
GenerateReport has no (N)RVO or any kind of elision, other than possibly under as-if. I doubt a compiler will be able to prove that, especially if the string is non-static and large enough to require heap storage.
For DoIt both NRVO and RVO is possible. Elision is legal there, even with side effects.
MSVC fails -- notice calls to
??0string##QAE#$QAU0##Z, which is the move constructor of my local string class.
When I force the possible RVO case to run by saying it is empty, you'll see that the compiler also fails to RVO optimize here; there is an exit(-1) inlined into the disassembly.
Clang manages to RVO the return string(); but not NRVO the return val;.
By far the easiest fix is:
string DoIt(bool remove_all)
{
if(g_report_generator.isEmpty())
return string();
return [&]{
string val = g_report_generator.GenerateReport();
if(remove_all)
g_report_generator.clear();
return val;
}();
}
which has double RVO, and a lambda that does simple NRVO. Zero structural changes to your code, and functions which C++98 compilers can elide return values on (well, they don't support lambda, but you get the idea).

I do not think (N)RVO is possible in either functions. GenerateReport has to construct a string from character array, there is nothing left for NRVO. DoIt returns two different values through it control path, which makes it impossible to perform NRVO as well.

Related

Most efficient way to mutate data member

I've been wondering about this question for a long time. What is the most idiomatic and / or efficient way to assign a new value to a data member (mutation)? I can think of 3 options:
Mutate directly from within method
Use a reference to mutate object
Assign the return value of the method to the data member (RVO)
Here's a demo. Please consider while reading the assembly that the compiler optimizes away probably most of the differences in this contrived example, but I just wanted to showcase the options in the most simple way. Please answer for the case where this methods are more involved.
Demo
#include <string>
#include <cstdio>
struct some_struct
{
auto assign_direct() {
str_ = "Hello World!";
}
auto assign_through_ref(std::string& ref) {
ref = "Hello World!";
}
auto assign_through_RVO() {
const std::string ret = "Hello World!";
return ret;
}
void internal_func() {
assign_direct();
assign_through_ref(str_);
str_ = assign_through_RVO();
}
std::string str_;
};
int main()
{
some_struct s;
s.internal_func();
}
My thought is that both, direct assignement and copy assignement must be equally efficient as they dereference the this-pointer and then dereference the effective address of the data member. So two dereferences are involved while the assign_thorugh_ref method only ever uses one dereferencing (except that this must be dereferenced to even call the method, but maybe this can be optimized away by an intelligent compiler).
Also what I want to know is what is most idiomatic / clear and least error prone? Maybe someone with some more years than me can give me some insights here!

Returning string constants in switch-case block with std::string

NOTE: This is not about using a string for choosing the execution path in a switch-case block.
A common pattern in C++ is to use a switch-case block for converting integer constants to strings. This looks like:
char const * to_string(codes code)
{
switch (code)
{
case codes::foo: return "foo";
case codes::bar: return "bar";
}
}
However, we are in C++, so using std::string is more appropriate:
std::string to_string(codes code)
{
switch (code)
{
case codes::foo: return "foo";
case codes::bar: return "bar";
}
}
This however copies the string literal. Perhaps a better approach would be instead:
std::string const & to_string(codes code)
{
switch (code)
{
case codes::foo: { static std::string str = "foo"; return str; }
case codes::bar: { static std::string str = "bar"; return str; }
}
}
But this is kinda ugly, and involves more boilerplate.
What is considered the cleanest and most efficient solution for this problem using C++14?
This however copies the string literal.
Yes and no. It will copy the string literal indeed, but don't necessarily allocate memory. Check your implementation SSO limit.
You could use std::string_view:
constexpr std::string_view to_string(codes code) {
switch (code) {
case codes::foo: return "foo";
case codes::bar: return "bar";
}
}
You can find many backported versions like this one
However, sometimes a char const* is the right abstraction. For example, if you were to forward that string into an API that require a null terminated string, you'd be better off returning it a c style string.
But this is kinda ugly, and involves more boilerplate.
What is considered the cleanest and most efficient solution for this problem using C++14?
To answer the above, as #SamerTufail pointed out (and as I do it myself at work also), I would use enums and std::map like this.
typedef enum {
foo = 1,
bar = 2,
} Key;
std::map<Key, std::string> hash_map = { {Key::foo ,"foo"}, { Key::bar,"bar"} };
And then in main() you could get the value like this,
std::cout << hash_map.find(Key::foo)->second;
I would create a function for returning the second, where you would check the iterator for end(), otherwise the interator would be invalid and using it would be UB.
EDIT: As others have pointed out in the comments and as per this question, you could replace std::map, with std::unordered_map provided you do not need to keep elements in order.
And as per my experience, I always create such maps as static const. Therefore create them one time and use them many times to amortize the cost of creation.
Assuming that you eventually want a std::string with the label in it, the question is whether to create them:
1: in to_string()
2: in its caller
Using Compiler Explorer it's pretty easy to find out.
Turns out (with recent compilers) that there's not a lot difference between the two. Returning const char * has a slight edge on std::string
1:
#include <string>
char const * to_string(int code)
{
switch (code)
{
case 0: return "foo";
case 1: return "bar";
}
}
std::string foo(int x)
{
std::string s{to_string(x)};
return s;
}
2:
#include <string>
std::string to_string2(int code)
{
switch (code)
{
case 0: return "foo";
case 1: return "bar";
}
}
std::string foo2(int x)
{
std::string s{to_string2(x)};
return s;
}
Note:
I needed to add foo() in order to stop the compiler optimising even more heavily....
In both cases, the strings are short and can use the short-string optimisation. Both clang and GCC have managed a heap-elision. This is seriously impressive - the compiler knows that to_string() never returns a string bigger than 4 bytes long and then eliminates the code that would dynamically allocate heap memory.
The conclusion seems to be that writing natural, and tidy code has little performance penalty.

Workaround for returning uncopyable object without a move ctor

In my API I have a function that returns std::istringstream.
The std::istringstream class is non-copyable but supports moving so on a conforming compiler there is no problem returning a local std::istringstream.
However, on gcc 4.9, there is no support for moving std::istringstream.
Is there some workaround that I can use that std::istringstream without changing the API from the user's perspective?
The workaround suggested here, of using a unique_ptr<std::istringstream> will change the semantics of the API.
If you can't move the std::istringstream, there's no much way around it.
If an object is non copiable and non movable, you can't return it by value.
If you want to support new features, you better get a new compiler for those.
In the meatime, you could return a unique_ptr. If you're really eager to return by value, you could return a movable wrapper that contains a std::unique_ptr<std::istringstream> and provide the same interface as a istringstream. However, this also affect the return type.
It may be tempting to return by rvalue reference. Here's what you can do:
struct MyApiClass {
std::istringstream&& get_stream() {
return std::move(*_stream);
}
private:
std::unique_ptr<std::istringstream> _stream;
};
Then, with your old compiler, you can use it like this:
std::istringstream&& stream = myApiClass.get_stream();
// use stream as long as myApiClass exists
People using a new compiler will be able to use it like that:
std::istringstream stream = myApiClass.get_stream();
// use stream normally
This is the way the api is less affected. Other than that, I don't know any workaround.
The way to return class without move/copy constructor is to use the return statement with braced-init-list:
class C {
C() = default;
C(const C&) = delete;
C(C&&) = delete;
};
C make_C() { return {}; }
int main() {
C&& c = make_C();
}
Demo
Unfortunately, only non-explicit constructor are considered for this initialization and std::istringstream have explicit constructor.
One workaround is to create a sub-class with non explicit constructor:
struct myIStringStream : std::istringstream
{
myIStringStream () = default;
};
myIStringStream make_istringstream()
{
return {};
}
int main()
{
std::istringstream&& iss = make_istringstream();
}
Demo
Answering my own question for completeness and future reference.
The goal was to find a workaround for the gcc (< 5) bug where std::istringstream does not provide a move ctor that will work in cases where I want to return the un-copyable and (bugly-) unmovable stream.
As mentioned in the comments, I can in fact change my function signature (at least on gcc < 5) to return a proxy object that allows copying or moving without changing the API for code used on newer/other compilers.
The idea, suggested and implemented by a colleague, is to create a proxy object around std::istringstream which provides a similar API, but also provides a copy-ctor which manually creates and initializes a new internal std::istringstream from the copied-from stream. This proxy is used only on the offending compilers.
The code in its natural habitat is here.
Here's the relevant part:
#if !defined(__GNUC__) || (__GNUC__ >= 5)
using string_stream = std::istringstream;
#else
// Until GCC 5, istringstream did not have a move constructor.
// stringstream_proxy is used instead, as a workaround.
class stringstream_proxy
{
public:
stringstream_proxy() = default;
// Construct with a value.
stringstream_proxy(std::string const& value) :
stream_(value)
{}
// Copy constructor.
stringstream_proxy(const stringstream_proxy& other) :
stream_(other.stream_.str())
{
stream_.setstate(other.stream_.rdstate());
}
void setstate(std::ios_base::iostate state) { stream_.setstate(state); }
// Stream out the value of the parameter.
// If the conversion was not possible, the stream will enter the fail state,
// and operator bool will return false.
template<typename T>
stringstream_proxy& operator >> (T& thing)
{
stream_ >> thing;
return *this;
}
// Get the string value.
std::string str() const { return stream_.str(); }
std::stringbuf* rdbuf() const { return stream_.rdbuf(); }
// Check the state of the stream.
// False when the most recent stream operation failed
operator bool() const { return !!stream_; }
~stringstream_proxy() = default;
private:
std::istringstream stream_;
};
using string_stream = stringstream_proxy;
#endif

const auto& for storing functions results, is it worthwhile?

Let assume that we have a function that returns a complex object like std::string:
std::string find_path(const std::string& filename);
Is it worthwhile to store the result of calling that method in the const auto&?
void do_sth() {
//...
const auto& path = find_path(filename);
//...
}
That kind of approach prevents copying/moving the object. So it is good. But on the other hand, auto has been introduced to unify the left side of assignation. Herb Sutter in his presentation from CppCon2014 mentions about C++ left-to-right modern style https://www.youtube.com/watch?v=xnqTKD8uD64 (39:00-45:00).
In C++98 storing the std::string at const ref was fine. How is it in C++11?
Update (2016-07-27 2:10 GMT+0):
Sorry, my question was not precise. I meant the coding style - is it better to add const & or just stay with auto only and let the compiler do whatever it want.
Updated example:
unsigned int getTimout() { /* ... */ }
int getDepth() { /* ... */ }
std::string find_path(const std::string& filename,
unsigned int timeout,
int depth) { /* ... */ }
void open(const std::string& path) { /* ... */ }
Two approaches:
void do_sth() {
//...
auto timeout = getTimeout();
auto depth = getDepth();
const auto& path = find_path(filename, timeout, depth);
open(path)
//...
}
vs
void do_sth() {
//...
auto timeout = getTimeout();
auto depth = getDepth();
auto path = find_path(filename, timeout, depth);
open(path);
//...
}
The question: should we
use const auto& to store complex return objects and auto for primitives, or
use auto for everything to keep the left-to-right modern C++ style that Herb mentioned in his presentation (link above).
In C++98 storing the std::string at const ref was fine. How is it in C++11?
Binding a const reference to a temporary string object is fine in C++11. It still has the same behaviour as before.
The theoretical cost of copy-initialization from a temporary (avoiding of which is the advantage of using a const reference) has been greatly reduced in C++11, since moving a string is far cheaper than copying.
The practical cost of copy-initialization has not changed with optimizing compilers, because they may elide the copy/move anyway, so there is no cost - although, whether that is possible, depends on how find_path is implemented.
If you absolutely want to avoid copying/moving the returned string and cannot assume copy elision, then you must create the object outside the function, and pass it to the function by reference. Binding a reference to the return value is not sufficient.
If you want to avoid copying/moving the returned string and can assume copy elision, then using a regular object is just as good as a const reference.

How do I reserve space on the stack for a non-default constructible?

I would basically write the following piece of code. I understand why it can't compile.
A instance; // A is a non-default-constructable type and therefore can't be allocated like this
if (something)
{
instance = A("foo"); // use a constructor X
}
else
{
instance = A(42); // use *another* constructor Y
}
instance.do_something();
Is there a way to achieve this behaviour without involving heap-allocation?
There are better, cleaner ways to solve the problem than explicitly reserving space on the stack, such as using a conditional expression.
However if the type is not move constructible, or you have more complicated conditions that mean you really do need to reserve space on the stack to construct something later in two different places, you can use the solution below.
The standard library provides the aligned_storage trait, such that aligned_storage<T>::type is a POD type of the right size and alignment for storing a T, so you can use that to reserve the space, then use placement-new to construct an object into that buffer:
std::aligned_storage<A>::type buf;
A* ptr;
if (cond)
{
// ...
ptr = ::new (&buf) A("foo");
}
else
{
// ...
ptr = ::new (&buf) A(42);
}
A& instance = *ptr;
Just remember to destroy it manually too, which you could do with a unique_ptr and custom deleter:
struct destroy_A {
void operator()(A* a) const { a->~A(); }
};
std::unique_ptr<A, destroy_A> cleanup(ptr);
Or using a lambda, although this wastes an extra pointer on the stack ;-)
std::unique_ptr<A, void(*)(A*)> cleanup(ptr, [](A* a){ a->~A();});
Or even just a dedicated local type instead of using unique_ptr
struct Cleanup {
A* a;
~Cleanup() { a->~A(); }
} cleanup = { ptr };
Assuming you want to do this more than once, you can use a helper function:
A do_stuff(bool flg)
{
return flg ? A("foo") : A(42);
}
Then
A instance = do_stuff(something);
Otherwise you can initialize using a conditional operator expression*:
A instance = something ? A("foo") : A(42);
* This is an example of how the conditional operator is not "just like an if-else".
In some simple cases you may be able to get away with this standard C++ syntax:
A instance=something ? A("foo"):A(42);
You did not specify which compiler you're using, but in more complicated situations, this is doable using the gcc compiler-specific extension:
A instance=({
something ? A("foo"):A(42);
});
This is a job for placement new, though there are almost certainly simpler solutions you could employ if you revisit your requirements.
#include <iostream>
struct A
{
A(const std::string& str) : str(str), num(-1) {};
A(const int num) : str(""), num(num) {};
void do_something()
{
std::cout << str << ' ' << num << '\n';
}
const std::string str;
const int num;
};
const bool something = true; // change to false to see alternative behaviour
int main()
{
char storage[sizeof(A)];
A* instance = 0;
if (something)
instance = new (storage) A("foo");
else
instance = new (storage) A(42);
instance->do_something();
instance->~A();
}
(live demo)
This way you can construct the A whenever you like, but the storage is still on the stack.
However, you have to destroy the object yourself (as above), which is nasty.
Disclaimer: My weak placement-new example is naive and not particularly portable. GCC's own Jonathan Wakely posted a much better example of the same idea.
std::experimental::optional<Foo> foo;
if (condition){
foo.emplace(arg1,arg2);
}else{
foo.emplace(zzz);
}
then use *foo for access. boost::optional if you do not have the C++1z TS implementation, or write your own optional.
Internally, it will use something like std aligned storage and a bool to guard "have I been created"; or maybe a union. It may be possible for the compiler to prove the bool is not needed, but I doubt it.
An implementation can be downloaded from github or you can use boost.