#include <iostream>
using namespace std;
class Foo
{
public:
Foo()
{
cout << 0;
}
Foo(Foo &f)
{
cout << 1;
}
};
void someFunction(Foo f) {};
int main()
{
Foo f1; //displays 0 (as expected)
Foo f2(f1); //displays 1 (as expected)
someFunction(f1); //displays 1 (why?)
someFunction(f2); //displays 1 (why?)
return 0;
}
I don't understand why function 'someFunction' calls second constructor. I thought it will just call first constructor, with no parameters, and displays 0.
Maybe I am missing something obvious...
The second constructor is a copy constructor, and when you pass an argument to a function by value it is copied, which invokes the copy constructor.
The first constructor (the default constructor) is only called when creating an object from scratch, and without any arguments.
Because when you call someFunction, the compiler invokes the copy-constructor to copy the object f1 or f2 into f.
To avoid that, just declare the function with a reference parameter to a Foo object, like so:
int someFunction(Foo &f) {}
Then call it as usual:
someFunction(f1);
It will never call default constructor because you are just copying foo object. It will use copy constructor and if there is no copy contructor available, it is using the second which is similar to that.
Related
I have this simple piece of code in C++17 and I was expecting that the move constructor was called (or the copy constructor, if I was doing something wrong), while it is just calling the normal constructor and I cannot why is doing this optimization.
I am compiling with -O0 option.
#include <iostream>
using namespace std;
struct Foo {
int m_x;
Foo(int x) : m_x(x) { cout << "Ctor" << endl; }
Foo(const Foo &other) : m_x(other.m_x) { cout << "Copy ctor" << endl; }
Foo(Foo &&other) : m_x(other.m_x) {
other.m_x = 0;
cout << "Move ctor" << endl;
}
};
void drop(Foo &&foo) {}
int main() { drop(Foo(5)); }
I cannot why is doing this optimization.
This is not due to any optimization in C++17. Instead this is due to the fact that you're passing an int when you wrote Foo(5). And since you've provided a converting constructor Foo::Foo(int), it will be used to create a Foo object which will then be bound to the rvalue reference parameter of drop.
Note that in C++17, even if we were to make the parameter of drop to be of type Foo instead of Foo&&, then also there will be no call to the move constructor because of mandatory copy elison.
C++11
On the other hand, if you were using C++11 and using the flag -fno-elide-constructors and parameter to drop was of type Foo instead of Foo&& then you could see that a call would be made to the move ctor.
//--------vvv-----------> parameter is of type Foo instead of Foo&&
void drop(Foo foo) {
std::cout<<"drop called"<<std::endl;
}
int main() {
drop(Foo(5)); //in c++11 with -fno-elide-constructors the move ctor will be called
}
The output of the above modified version in C++11 with -fno-elide-constructors is:
Ctor
Move ctor
drop called
Demo
In function main you create a temporary Foo object from integer 5 but you don't move (nor copy) from it anywhere. To actually call your move (or copy) constructor, you have to move- (or copy-) construct another object from your temporary Foo.
E.g., to call Foo's move constructor:
void drop(Foo &&foo) {
// Move-construct tmp from foo.
Foo tmp { std::move(foo) };
}
CPP Core guidelines F45 states:
Don't return a T&&.
I want to create some class, and pass the class through a sequence of functions that modify the class. Then I will either evaluate some members of that class, or store the class in some container, like std::vector.
I am trying to do this in a way that the class is constructed exactly once, then destroyed, or moved and the moved-from copy is destroyed, and later the stored copy is destroyed (when the container that I stored it in is destroyed).
In essence, I want to do this:
// some class
class foo{}
// construct a foo, with some parameters, and modify it somehow
auto f1 = modify_foo(foo(x, y, z));
// modify the foo some more
auto f2 = modify_foo(f1);
// modify the foo some more
auto f3 = modify_foo(f2);
// use some element of modified foo
auto v = f3.getx();
// maybe store the modified foo in a vector or some other container
vector<foo> vf;
vf.emplace_back(f3);
It should be possible to construct the foo exactly once, and move the constructed foo through any number of modifying functions, then destroy the foo exactly once.
In the case of storing the foo in a vector, an additional copy/move and destroy will have to occur.
I can achieve this behavior, but I can't figure out any way to do it without using this signature for the modify functions:
foo&& modify_foo(foo&& in);
Here is test code that seems to do what I want:
#include <iostream>
#include <functional>
#include <vector>
// A SIMPLE CLASS WITH INSTRUMENTED CONSTRUCTORS
class foo {
public:
// default constructor
foo() {
std::cout << "default construct\n";
}
// copy constructor
foo(foo const &in) : x{ in.x } {
std::cout << "copy construct\n";
};
// copy assignment
foo& operator=(foo const& in) {
x = in.x;
std::cout << "copy assignment\n";
}
// move constructor
foo(foo&& in) noexcept : x(std::move(in.x)) {
std::cout << "move constructor\n";
}
// move assignment
foo& operator=(foo&& in) noexcept {
x = std::move(in.x);
std::cout << "move assignment\n";
return *this;
}
// destructor
~foo() {
std::cout << "destructor\n";
}
void inc() {
++x;
}
int getx() { return x; };
private:
int x{ 0 };
};
Now a function that will take foo&&, modify foo, return foo&&:
// A SIMPLE FUNCTION THAT TAKES foo&&, modifies something, returns foo&&
foo&& modify(foo&& in) {
in.inc();
return std::move(in);
}
Now using the class and modify function:
int main(){
// construct a foo, modify it, return it as foo&&
auto&& foo1 = modify(foo());
// modify foo some more and return it
auto&& foo2 = modify(std::move(foo1));
// modify foo some more and return it
auto&& foo3 = modify(std::move(foo2));
// do something with the modified foo:
std::cout << foo3.getx();
}
This will do exactly what I want. It will call the constructor once, correctly print 3, and call the destructor once.
If I do the same thing, except add this:
std::vector<foo> fv;
fv.emplace_back(std::move(foo3));
It will add one move construct, and another destruct when the vector goes out of scope.
This is exactly the behavior I want, and I haven't figured out any other way to get there without returning foo&& from the modifier, and using auto&& for my intermediate variables, and using std::move() on the parameters being passed to the subsequent calls to modify.
This pattern is very useful to me. It is bothering me that I can't resolve this with CPP core guidelines F.45. The guideline does say:
Returning an rvalue reference is fine when the reference to the temporary is being passed "downward" to a callee; Then the temporary is guaranteed to outlive the function call...
Maybe that is what I am doing?
My questions:
Is there anything fundamentally wrong, or undefined, in what I am doing?
When I do auto&&, and hover over the foo1, it will show it as a foo&&. I still have to wrap the foo1 with std::move(foo1) to get the modify function to accept it as foo&&. I find this a little strange. What is the reason for requiring this syntax?
As was correctly pointed out by NathanOliver, attempting to use rvalue ref's was leaving a dangling reference to an object that was being destroyed at the end of the function's life.
The piece of the puzzle that I was missing was to use 'auto&', instead of 'auto' when returning a ref from a function:
// function taking lvalue ref, returning lvalue ref
foo& modify(foo& in) {
in.inc();
return in;
}
{
auto f = foo{}; // constructed here
auto f1 = modify(f); // <-- BAD!!! copy construct occurs here.
auto& f2 = modify(f); // <-- BETTER - no copy here
} // destruct, destruct
If I use auto& to capture the lvalue ref returning from 'modify', no copies are made. Then I get my desired behavior. One construct, one destruct.
{
// construct a foo
foo foo1{};
// modify some number of times
auto& foo2 = modify(std::move(foo1));
auto& foo3 = modify(std::move(foo2));
auto& foo4 = modify(std::move(foo3));
std::cout << foo4.getx();
} // 1 destruct here
I have a optional member in a class, which I want to return by value, via a method.
Sample code:
#include <stdio.h>
#include <optional>
#include <iostream>
using namespace std;
class bar {
public:
int a;
bar(const bar &obj) {
a = obj.a;
}
};
class foo {
public:
void init(){
abc->a = 100;
}
optional<bar> get() {
return abc;
}
optional<bar> abc;
};
int main()
{
foo temp;
temp.init();
auto copied = temp.get();
cout << "Expected value is 100, got: " << copied->a;
return 0;
}
The code outputs some garbage value.
How may I achieve this?
From my understanding, optional stores a fully allocated memory for the underlying type (not just a reference), and while returning a optional variable, the copy constructor of the underlying type should kick in, which should copy the memory as-is to the new optional value being returned.
You need to use the constructor of optional to ensure that it contains an object: (assuming that the redundant copy constructor of bar, which blocks it from being constructed, is removed)
foo()
: abc{bar{100}}
{
}
or, after the optional has been created:
void init(){
abc = bar{100};
}
Otherwise, the optional is kept in an empty state, and invoking -> on an empty optional results in undefined behavior. The copy constructor of optional does not copy construct a contained object when the source is empty.
std::optional is like a smart pointer, it defaults to a "null" value and accessing its members would therefore be undefined behaviour. You need to initialise it before use:
void init(){
abc = bar();
abc->a = 100;
}
Note that as it stands bar isn't constructible other than via the copy constructor so you need to add a default constructor or a constructor that takes an int argument or remove the unnecessary copy constructor.
My confusion lies at line Cube c = a;. I think it should call both default constructor and copy constructor, but in fact it only calls copy constructor.
Isn't Cube c, just like Cube a, a new object that should invoke default constructor?
class Cube
{
public:
int length_;
Cube(){
length_ = 1;
cout<< "Default Constr"<< endl;
}
Cube(const Cube & obj){
length_ = obj.length_;
cout<< "Copy Constr"<< endl;
}
};
Cube foo(){
Cube c;
return c;
}
int main() {
Cube a; //invoke default constructor only
Cube c = a; //invoke copy constructor only
return 0;
}
As others have pointed out, what you have here is copy initialization, so there's no way a default constructor would be used.
There is a slightly different case in which copy initialization can (at least theoretically) involve an extra step. Consider code like this:
class foo {
public:
foo(int) {}
};
int main() {
foo f = 1;
}
In this case, (at least before C++17) there were theoretically supposed to be two separate constructors involved. First, a temporary was constructed, initialized with 1, then the copy constructor was called to initialize f from that temporary object.
In this case, most compilers will generate code that just directly initializes f from q, so it's equivalent to foo f{1};. The compiler is still required to respect the fact that a copy is needed though, so if you delete the copy constructor, compilation will fail:
class foo {
foo(foo const &)= delete;
public:
foo(int) {}
};
int main() {
foo f = 1;
}
Result (with gcc):
trash9.cpp: In function 'int main()':
trash9.cpp:8:17: error: use of deleted function 'foo::foo(const foo&)'
foo f = 1;
^
trash9.cpp:2:9: note: declared here
foo(foo const &) = delete;
^~~
trash9.cpp:4:9: note: after user-defined conversion: 'foo::foo(int)'
foo(int) {}
^~~
But changes in the rules starting with C++17 mean that now even that is allowed (so if I add -std=c++17 to the compilation above, it succeeds).
When you write:
Cube c = a;
This is actually not an assignment but a copy-initialization.
In your case, it would be the same as if you had written:
Cube c(a);
Only the copy-constructor is called.
Keep in mind that an object is constructed only once, therefore only one constructor.
The default constructor is called.
It is used to initialize the object.
Then the copy constructor is used to set the state of the new object to be the same with the initial one.
In the line commented by ***, why is Bar's copy constructor called? input_bar is a rvalue reference, so I expect the move constructor to be called. Did it convert to an lvalue reference? I can make the move constructor call if I change that line to bar_(std::move(input_bar)).
#include <iostream>
#include <array>
#include <memory>
class Bar
{
public:
Bar(const Bar& bar)
{
std::cout << "copy constructor called" << std::endl;
}
Bar(Bar&& bar)
{
std::cout << "move constructor called" << std::endl;
}
};
class Foo
{
public:
Foo(Bar&& input_bar) :
bar_(input_bar) // ***
{
}
Bar bar_;
};
int main()
{
Bar bar;
Foo foo(std::move(bar));
return 0;
}
Once an entity has a name, it is clearly an lvalue! If you have a name for an rvalue reference, the entity with the name is not an rvalue but an lvalue. The entire point is that you know that this entity references an rvalue and you can legitimately move its content.
If you want to just forward the rvalueness to the next function you call, you'd use std::move(), e.g.:
Foo(Bar&& bar): bar_(std::move(bar)) {}
Without the std::move() the rvalue is considered to be owned by the constructor. With the std::move() it releases the ownership and passes it on to the next function.
You have to move rhrs:
Foo(Bar&& input_bar) :
bar_(std::move(input_bar)) // ***
{
}
The reasoning is that once we actually use the RHR, it should be semantially treated as out of scope. Forcing you to use std::move allows the following code to not be undefined:
Foo(Bar&& input_bar) {
std::cout << input_bar.baz << std::endl;//not undefined
bar_ = Bar{std::move(input_bar)};//input_bar is now essentailly destroyted
//std::cout << input_bar.baz << std::endl;//Undefined behavior, don't do this
}
The general rule of thumb is that only things without names can actually be used as RHR's...RHR as arguments have names, and thus will be treated as LHR untill you call a function on them.