Does std::optional forwards rvalueness when contained object functions are called? - c++

Little known feature of C++ is ref-qualifiers for member functions.
It works as I expect it to work in most cases, but it seems that std::optional does not forward the knowledge of its imminent demise to contained object member functions.
For example consider the following code:
#include <chrono>
#include <iostream>
#include <optional>
struct Noisy {
Noisy(const std::string& data): data_(data){
}
~Noisy(){
std::cout << "Goodbye" << std::endl;
}
std::string data_;
const std::string& data() const & {
std::cout << "returning data by ref" << std::endl;
return data_;
}
std::string data() && {
std::cout << "returning data by move" << std::endl;
return std::move(data_);
}
};
int main() {
for (const auto chr: Noisy{"Heeeeeeeeeeeeeeeeello wooooorld"}.data()){
std::cout << chr;
}
std::cout << std::endl;
for (const auto chr: std::optional<Noisy>{"Heeeeeeeeeeeeeeeeello wooooorld"}->data()){
std::cout << chr;
}
std::cout << std::endl;
}
output is:
returning data by move
Goodbye
Heeeeeeeeeeeeeeeeello wooooorld
returning data by ref
Goodbye
(crash in clang with sanitizer or garbage(UB))
I was hoping that temporary std::optional will be kind enough to call correct (data() &&) function, but it seems it does not happen.
Is this a language limitation, or std::optional just does not have correct machinery for this?
Full godbolt link.
note: my motivation is hacking around to see if I can be clever to enable safer usage of my classes in range based for loop, but realistically it is not worth the effort, this question is mostly about learning about language.

Overloaded operator arrow cannot do what you want; it terminates with a pointer always.
x->y is defined by the standard as (*x).y if and only if x is a pointer; otherwise it is (x.operator->())->y. This recursion only terminates if you hit a pointer.1
And there is no pointer to temporary type. Try this:
const auto chr: (*std::optional<Noisy>{"Heeeeeeeeeeeeeeeeello wooooorld"}).data()
Which does call the rvalue method. (via #largest_prime).
1 This recursion can also do Turing complete computation.

Related

How to choose between `push_*()` and `emplace_*()` functions?

I understand the difference between the two function variants.
My question is: should I normally use good old push_*() version and only switch to emplace_*() when my profiler tells me this will benefit performance (that is, do not optimise prematurely)? Or should I switch to using emplace_*() as the default (perhaps not to pessimise the code unnecessarily - similar to i++ vs ++i in for loops)?
Is any of the variants more universal than the other (that is, imposes less constraints on the type being inserted) in realistic non-contrived use cases?
While writing the code I would not worry about performance. Performance is for later when you already have code that you can profile.
I'd rather worry about expressiveness of the code. Roughly speaking, push_back is for when you have an element and want to place a copy inside the container. emplace_back is to construct the element in place.
Consider what has the lower "wtf-count":
struct foo {int x;int y;};
void foo_add(const foo& f,std::vector<foo>& v) {
v.emplace_back(f); // wtf ?!? we already have a foo
v.push_back(f); // ... simply make a copy (or move)
}
void foo_add(int x, int y, std::vector<foo>& v) {
auto z = foo{x,y}; // wtf ?!?
f.push_back(z); // why create a temporary?
f.emplace_back(x,y); // ... simply construct it in place
}
emplace functions are delegating constructors.
Let's say you have a container of T.
If you already have a T, maybe it's const, maybe it's a rvalue, maybe none of those;
Then you use push_xxx().
Your object will be copied/moved into the container.
If you instead want to construct a T, then you use emplace_xxx(), with the same parameters you would send the constructor.
An object will be constructed directly in the container.
Emplace functions are more generic than push functions. In no case they are less efficient, on the contrary - they can be more efficient, as they allow to optimize away one copy/move operation of the container element when you need to construct it from arguments. When putting an element into container involves copy/move anyway, emplace and push operations are equivalent.
Push can be preferable, if you actually want to enforce construction before copying/moving the element into the container. For example, if your element type has some special logic in its constructor that you want to execute before the container is modified. Such cases are quite rare, though.
If you switch from push_back to emplace_back in a naive way, you will have no advantage at all. Consider the following code:
#include <iostream>
#include <string>
#include <vector>
struct President
{
std::string name;
std::string country;
int year;
President(std::string p_name, std::string p_country, int p_year) :
name(std::move(p_name)), country(std::move(p_country)), year(p_year)
{
std::cout << "I am being constructed.\n";
}
President(President&& other) :
name(std::move(other.name)), country(std::move(other.country)),
year(other.year)
{
std::cout << "I am being moved.\n";
}
President& operator=(const President& other) = default;
};
int main()
{
std::vector<President> elections;
std::cout << "emplace_back:\n";
elections.emplace_back("Nelson Mandela", "South Africa", 1994);
std::vector<President> reElections;
std::cout << "\npush_back:\n";
reElections.push_back(
President("Franklin Delano Roosevelt", "the USA", 1936));
std::cout << "\nContents:\n";
for (President const& president : elections)
{
std::cout << president.name << " was elected president of "
<< president.country << " in " << president.year << ".\n";
}
for (President const& president : reElections)
{
std::cout << president.name << " was re-elected president of "
<< president.country << " in " << president.year << ".\n";
}
}
If you replace push_back by emplace_back you still have a construction and then a move. Only if you pass the arguments needed for construction instead of the constructed instance itself (see the call to emplace_back), you have saved effort.

Relying on deterministic destruction, avoiding destruction on return

I have been trying to rework my logging class. However, I'm facing a problem.
I want to expose this interface to users:
mylog() << "hello";
The idea is that mylog is an instance of Logger, which defines some useful characteristics for a defined log type. Its operator() function would return an instace of type LogStream. However, I would like to output the newline character automatically at the end, so I had the idea to do that in LogStream's destructor.
My current implementation looks like this (LogStream and Logger being largely dumbed down):
#include <iostream>
struct LogStream
{
~LogStream() { std::cout << '\n'; }
template<class T>
LogStream& operator<<(const T& t)
{
std::cout << t;
return *this;
}
};
struct Logger
{
LogStream operator()()
{
return LogStream{} << "message: ";
}
};
int main()
{
Logger log;
log() << "hello!";
}
Interstingly, I figured out with this piece of code that my previous implementation depended on RVO. The compiler was always performing copy-elision, so the destructor did behave the way I want. However, with this piece of code, the newline character is being printed twice, because the copy constructor is being called when the copy occurs in operator().
The problem disappears when I do not return the temporary instance, and instead put this in operator()'s body:
LogStream stream;
stream << "message: ";
return stream;
Now the RVO makes it work the way I want.
I later on = delete'd the copy constructors, because it made more sense anyway, which effectively causes the code to fail to compile.
What are my options to provide the interface I want, without using the hacky solution to rely on RVO?
Add a constructor to LogStream that takes a char const *.
LogStream(char const* c) { std::cout << c; }
Then, instead of creating a temporary LogStream within operator(), use list-initialization to initialize the return value itself.
LogStream operator()()
{
return {"message: "};
}
The temporary is thus avoided along with the extra new line.
Live demo (note that even using -fno-elide-constructors to disable copy elision doesn't result in the extra newline).

Is it possible to avoid copying arguments to a lambda function?

I'd like to manage file descriptors using a Handle, and I want to use lambda expressions to process them. I'd like to use RAII to manage the underlying file descriptors. One option is to handle invalid values for descriptors (e.g. -1). However, I'd prefer for a handle to always be valid.
I've found that I can't seem to avoid invoking the copy constructor at least once. Here is a working example:
#include <fcntl.h>
#include <unistd.h>
#include <functional>
#include <system_error>
#include <iostream>
class Handle
{
public:
Handle(int descriptor) : _descriptor(descriptor) {}
~Handle()
{
std::cerr << "close(" << _descriptor << ")" << std::endl;
::close(_descriptor);
}
Handle(const Handle & other) : _descriptor(::dup(other._descriptor))
{
std::cerr << "dup(" << other._descriptor << ") = " << _descriptor << std::endl;
if (_descriptor == -1) throw std::system_error(errno, std::generic_category(), "dup");
}
int descriptor() const { return _descriptor; }
private:
int _descriptor;
};
Handle open_path(const char * path)
{
return ::open("/dev/random", O_RDONLY);
}
void invoke(std::function<void()> & function)
{
function();
}
int main(int argc, const char * argv[]) {
// Using auto f = here avoids the copy, but that's not helpful when you need a function to pass to another function.
std::function<void()> function = [handle = open_path("/dev/random")]{
std::cerr << "Opened path with descriptor: " << handle.descriptor() << std::endl;
};
invoke(function);
}
The output of this program is:
dup(3) = 4
close(3)
Opened path with descriptor: 4
close(4)
I know that the handle is being copied because it's being allocated by value within the std::function, but I was under the impression std::function could be heap allocated in some cases, which would perhaps avoid the copy (I guess this is not happening though).
There are a number of options, e.g. heap allocation, orusing a sentinel value (e.g. -1) which is checked. However, I'd like to have an invariant that a handle is always valid. It's sort of a matter of style and invariants.
Is there any way to construct the handle within the stack frame of the std::function to avoid copying, or do I need to take a different approach?
Perhaps as an additional point: to what extent can we rely on std::function to avoid copying it's arguments when it's created?
First, let's get this out of the way: std::function is completely orthogonal to lambdas. I wrote an article, "passing functions to functions" that should clarify their relationship and illustrate various techniques that can be used to implement higher-order functions in modern C++.
Using auto f = here avoids the copy, but that's not helpful when you need a function to pass to another function.
I disagree. You can use a template in invoke or something like function_view (see LLVM's FunctionRef for a production-ready implementation, or my article for another simple implementation):
template <typename F>
void invoke(F&& function)
{
std::forward<F>(function)();
}
void invoke(function_view<void()> function)
{
function();
}
Relying on elision or moving with std::function is not enough. Since std::function is required to be copyable, there's always a chance you might copy your Handle by accident elsewhere.
What you need to do instead is to wrap your Handle in something that will not invoke the copy constructor on copy. An obvious choice is a pointer. And an obvious choice of pointer would be a manged one like std::shared_ptr.
I made a few changes to your Handle class for testing (print statements for dtor, ctor, copy ctor), so I'll show those first:
class Handle
{
public:
Handle(int descriptor) : _descriptor(descriptor) {std::cerr<<"Default ctor, descriptor: " << _descriptor << std::endl;}
~Handle()
{
std::cerr << "Dtor. close(" << _descriptor << ")" << std::endl;
}
Handle(const Handle & other) : _descriptor(other._descriptor+1)
{
std::cerr << "Copy ctor. dup(" << other._descriptor << ") = " << _descriptor << std::endl;
}
int descriptor() const { return _descriptor; }
private:
int _descriptor;
};
Next let's modify open_path to return a shared_ptr:
std::shared_ptr<Handle> open_path(const char * path)
{
return std::make_shared<Handle>(0);
}
And then we'll make a slight modification to our lambda in main:
std::function<void()> function = [handle = open_path("/dev/random")]{
std::cerr << "Opened path with descriptor: " << handle->descriptor() << std::endl;
};
Our output now becomes:
Default ctor, descriptor: 0
Opened path with descriptor: 0
Dtor. close(0)
Live Demo

Is std::cout guaranteed to be initialized?

What I know about C++ is that the order of the constructions (and destructions) of global instances should not be assumed.
While I'm writing code with a global instance which uses std::cout in the constructor & destructor, I got a question.
std::cout is also a global instance of iostream. Is std::cout guaranteed to be initialized before any other global instances?
I wrote a simple test code and it works perfectly, but still I don't know why.
#include <iostream>
struct test
{
test() { std::cout << "test::ctor" << std::endl; }
~test() { std::cout << "test::dtor" << std::endl; }
};
test t;
int main()
{
std::cout << "Hello world" << std::endl;
return 0;
}
It prints
test::ctor
Hello world
test::dtor
Is there any possibility that the code doesn't run as expected?
The answer differs depending on if you're using C++03 or C++11.
In C++11, your code is guaranteed to work, but in C++03 it's unspecified; your only guarantee is that by the time main() is entered, the standard streams had been initialized. (That said, all mainstream implementations initialize them prior to running any dynamic initialization, making them fine to use.)
You can force initialization by constructing an std::ios_base::Init object, like so:
#include <iostream>
struct test
{
test() { std::cout << "test::ctor" << std::endl; }
~test() { std::cout << "test::dtor" << std::endl; }
private:
std::ios_base::Init mInitializer;
};
test t;
int main()
{
std::cout << "Hello world" << std::endl;
return 0;
}
Now when test constructs, it initializes mInitializer and guarantees the streams are ready to use.
C++11 fixed this slightly annoying behavior by acting as if every instance of #include <iostream> were followed by static std::ios_base::Init __unspecified_name__;. This automatically guarantees the streams are ready to use.
According to ยง27.3/2:
The objects [std::cin, std::cout, etc.] are constructed, and the
associations are established at some time prior to or during first
time an object of class ios_base::Init is constructed, and in any case
before the body of main begins execution.
Your question is about the order of construction of static objects. I believe that the language specification leaves it undefined.
GCC has the init_priority attribute to play with the order.
And I believe you should not worry that much in practice.

Efficient push_back of classes and structs

I've seen my colleague do the second snippet quite often. Why is this? I've tried adding print statements to track the ctors and dtors, but both seem identical.
std::vector<ClassTest> vecClass1;
ClassTest ct1;
ct1.blah = blah // set some stuff
...
vecClass1.push_back(ct1);
std::vector<ClassTest> vecClass2;
vecClass2.push_back(ClassTest());
ClassTest& ct2 = vecClass2.back();
ct2.blah = blah // set some stuff
...
PS. I'm sorry if the title is misleading.
Edit:
Firstly, thank you all for your responses.
I've written a small application using std::move. The results are surprising to me perhaps because I've done something wrong ... would someone please explain why the "fast" path is performing significantly better.
#include <vector>
#include <string>
#include <boost/progress.hpp>
#include <iostream>
const std::size_t SIZE = 10*100*100*100;
//const std::size_t SIZE = 1;
const bool log = (SIZE == 1);
struct SomeType {
std::string who;
std::string bio;
SomeType() {
if (log) std::cout << "SomeType()" << std::endl;
}
SomeType(const SomeType& other) {
if (log) std::cout << "SomeType(const SomeType&)" << std::endl;
//this->who.swap(other.who);
//this->bio.swap(other.bio);
this->who = other.who;
this->bio = other.bio;
}
SomeType& operator=(SomeType& other) {
if (log) std::cout << "SomeType::operator=()" << std::endl;
this->who.swap(other.who);
this->bio.swap(other.bio);
return *this;
}
~SomeType() {
if (log) std::cout << "~SomeType()" << std::endl;
}
void swap(SomeType& other) {
if (log) std::cout << "Swapping" << std::endl;
this->who.swap(other.who);
this->bio.swap(other.bio);
}
// move semantics
SomeType(SomeType&& other) :
who(std::move(other.who))
, bio(std::move(other.bio)) {
if (log) std::cout << "SomeType(SomeType&&)" << std::endl;
}
SomeType& operator=(SomeType&& other) {
if (log) std::cout << "SomeType::operator=(SomeType&&)" << std::endl;
this->who = std::move(other.who);
this->bio = std::move(other.bio);
return *this;
}
};
int main(int argc, char** argv) {
{
boost::progress_timer time_taken;
std::vector<SomeType> store;
std::cout << "Timing \"slow\" path" << std::endl;
for (std::size_t i = 0; i < SIZE; ++i) {
SomeType some;
some.who = "bruce banner the hulk";
some.bio = "you do not want to see me angry";
//store.push_back(SomeType());
//store.back().swap(some);
store.push_back(std::move(some));
}
}
{
boost::progress_timer time_taken;
std::vector<SomeType> store;
std::cout << "Timing \"fast\" path" << std::endl;
for (std::size_t i = 0; i < SIZE; ++i) {
store.push_back(SomeType());
SomeType& some = store.back();
some.who = "bruce banner the hulk";
some.bio = "you do not want to see me angry";
}
}
return 0;
}
Output:
dev#ubuntu-10:~/Desktop/perf_test$ g++ -Wall -O3 push_back-test.cpp -std=c++0x
dev#ubuntu-10:~/Desktop/perf_test$ ./a.out
Timing "slow" path
3.36 s
Timing "fast" path
3.08 s
If the object is more expensive to copy after "set some stuff" than before, then the copy that happens when you insert the object into the vector will be less expensive if you insert the object before you "set some stuff" than after.
Really, though, since you should expect objects in a vector to be copied occasionally, this is probably not much of an optimization.
If we accept that your colleague's snippet is wise, because ClassTest is expensive to copy, I would prefer:
using std::swap;
std::vector<ClassTest> vecClass1;
ClassTest ct1;
ct1.blah = blah // set some stuff
...
vecClass1.push_back(ClassTest());
swap(ct1, vecClass1.back());
I think it's clearer, and it may well be more exception-safe. The ... code presumably allocates resources and hence could throw an exception (or else what's making the fully-built ClassTest so expensive to copy?). So unless the vector really is local to the function, I don't think it's a good idea for it to be half-built while running that code.
Of course this is even more expensive if ClassTest only has the default swap implementation, but if ClassTest doesn't have an efficient swap, then it has no business being expensive to copy. So this trick perhaps should only be used with classes known to be friendly, rather than unknown template parameter types.
As Gene says, std::move is better anyway, if you have that C++0x feature.
If we're worried about ClassTest being expensive to copy, though, then relocating the vector is a terrifying prospect. So we should also either:
reserve enough space before adding anything,
use a deque instead of a vector.
The second version benefits from moving the temporary. The first version is copying the temporary vector. So the second one is potentially faster. The second version has also potentially smaller peak memory requirements, the first version creates two objects one temporary and one copy of it and only then deletes the temporary. You can improve the first version by explicitly moving the temporary:
std::vector<ClassTest> vecClass1;
ClassTest ct1;
ct1.blah = blah // set some stuff
...
vecClass1.push_back(std::move(ct1));
You should probably ask your collegue to know exactly why, but we can still take a guess. As James pointed out, it might be a tad more efficient if the object is more expensive to copy once constructed.
I see advantages in both versions.
I like your collegue's snippet because: although there are 2 objects in both cases, they only co-exist for a very short period of time in the second version. There is only one object available for editing: this avoids the potential error of editing ct1 after push_back.
I like your personal snippet because: invoking push_back to add a second object potentially invalidates the reference ct2, inducing a risk of undefined behavior. The first snippet does not present this risk.
They are identical (as far as I can see). Maybe he or she does that as an idiomatic custom.