I am trying to make a vector out of several integers by overloading the operator << and conversion operator.
However, when I test my code, I observe some absurd results.
The printed output should be 1 2 3 4.
But it actually print out something like this: 28495936 0 3 4.
The first two elements (e.g, 1 and 2) that were supposed to be pushed into the vector is lost or polluted.
I would appreciate it if someone can help me to figure it out the reason behind this.
#include <iostream>
#include <vector>
using namespace std;
template<typename T>
class make_vector {
public:
typedef make_vector<T> my_type;
my_type& operator<<(const T& val)
{
data_.push_back(val);
return *this;
}
operator std::vector<T>&()
{
return this->data_;
}
private:
std::vector<T> data_;
};
int main() {
std::vector<int>& A2 = make_vector<int>() << 1 << 2 << 3 << 4;
for (std::vector<int>::iterator it = A2.begin(); it != A2.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
You are binding a lvalue reference to a temporary:
std::vector<int>& A2 = make_vector<int>() << 1 << 2 << 3 << 4;
Note that, as #T.C. mentions in comments, it is your conversion operator that enables this. Without it the statement above would be invalid C++.
The issue with your code is that after this line, A2 refers to a defunct object.
It seems to me you don't want to use a reference:
std::vector<int> A2 = make_vector<int>() << 1 << 2 << 3 << 4;
You have a dangling reference here. It references a temporary.
std::vector<int>& A2 = make_vector<int>()....
You have two options:
You can copy the temp into a new, local variable.
std::vector<int> A2 = make_vector<int>()....
Or use a const ref. C++ grants a special rule to allow const references to extend the lifetime of a temporary.
const std::vector<int>& A2 = make_vector<int>()....
Your make_vector is badly designed and dangerous to use. You made it convertible to std::vector<T>& referring to its vector member, even if the make_vector object is a temporary. This is a dangling reference waiting to happen, since with this setup the compiler won't complain when you do things like
std::vector<int>& A2 = make_vector<int>() << 1 << 2 << 3 << 4;
because everything in this line is perfectly valid. Except that it leaves A2 a dangling reference as the make_vector temporary - and the vector it contains - gets destroyed at the ;. Ouch.
A better design would ref-qualify and overload your operator<< and the conversion function:
my_type& operator<<(const T& val) &
{
data_.push_back(val);
return *this;
}
my_type&& operator<<(const T& val) &&
{
data_.push_back(val);
return std::move(*this);
}
operator std::vector<T>&() &
{
return this->data_;
}
operator std::vector<T>() &&
{
return std::move(this->data_);
}
First, we make only lvalue make_vectors convertible to an lvalue reference to the underlying vector, since this is probably safe. For rvalue make_vectors, such as temporaries, we make the conversion function return the vector by value by moving from the underlying vector.
Second, we overload operator<< to preserve the value category of the make_vector object it is invoked on - it returns an lvalue reference if invoked on an lvalue, and an rvalue reference if invoked on an rvalue. This way, make_vector<int>() << 1 << 2 << 3 << 4 remains an rvalue.
Now errors like std::vector<int>& A2 = make_vector<int>() << 1 << 2 << 3 << 4; won't compile, while both
std::vector<int> A2 = make_vector<int>() << 1 << 2 << 3 << 4;
and
const std::vector<int> & A2 = make_vector<int>() << 1 << 2 << 3 << 4;
will and both are safe. (In the second case, the const reference binds to the temporary returned by operator std::vector<int>(), which extends the lifetime of the temporary.)
Related
This question refers to Howard Hinnant's answer to the question Guaranteed elision and chained function calls.
At the bottom of his answer, he says:
Note that in this latest design, if your client ever does this:
X&& x = a + b + c;
then x is a dangling reference (which is why std::string does not do this).
The paragraph "Lifetime of a temporary" of the article "Reference initialization" on cppreference.com lists exceptions to the lifetime rules of temporary objects bound to a reference. One being:
"a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call: if the function returns a reference, which outlives the full expression, it becomes a dangling reference."
I think it is rather meant "if the function returns a reference to the temporary object the reference parameter is bound to", not just some other reference. As a consequence, I reckon this is the rule that explains Howard Hinnant's above-mentioned statement.
The following example is based on the example given in the question that I am referring to:
struct X
{
int _x;
X() : _x(0) {}
X(int x) : _x(x) {}
X(X const& other) : _x(other._x) {}
X(X&& other) noexcept : _x(other._x) { other._x = 0; std::cout << "Move from " << &other << " to " << this << std::endl; }
X& operator+=(const X& other) { _x += other._x; return *this; }
friend X operator+(X const& lhs, X const& rhs)
{
std::cout << "X const& lhs: " << &lhs << std::endl;
X temp = lhs;
temp += rhs;
return temp;
}
friend X&& operator+(X&& lhs, X const& rhs)
{
std::cout << "X&& lhs: " << &lhs << std::endl;
lhs += rhs;
return std::move(lhs);
}
};
int anotherFunc(int a)
{
int bigArray[3000]{};
std::cout << "ignore:" << &bigArray << std::endl;
int b = a * a;
std::cout << "int b: " << &b << std::endl;
return 2 * b;
}
int main()
{
X a(1), b(2), c(3), d(4);
X&& sum = a + b + c + d;
std::cout << "X&& sum: " << &sum << std::endl;
anotherFunc(15);
std::cout << "sum._x: " << sum._x << std::endl;
return 0;
}
This prints
X const& lhs: 000000907DAFF8B4
Move from 000000907DAFF794 to 000000907DAFFA14
X&& lhs: 000000907DAFFA14
X&& lhs: 000000907DAFFA14
X&& sum: 000000907DAFFA14
ignore:000000907DAFC360
int b: 000000907DAFF254
sum._x: 10
when compiled with MSVC; and similar outputs when compiled with gcc or clang.
sum should be a dangling reference here. Still, the correct value "10" is being printed. It even works when pushing a large array onto the stack between the reference initialization of sum and the access via said reference. The memory used for the temporary object that sum refers does not get reused and is always allocated elsewhere (in relation to the stack frame of the following function call), no matter how big or small the next stack frame is.
Why does every compiler that I've tested preserve the temporary object local to X&& operator+(X&& lhs, X const& rhs) even though sum should be a dangling reference according to the rule on cppreference.com. Or, to be more precise: Despite accessing a dangling reference being undefined behaviour, why does every compiler implement it that way?
I like to keep an example class A around for situations like this. The full definition of A is a little too lengthy to list here, but it is included in its entirety at this link.
In a nutshell, A keeps a state and a status, and the status can be one of these enums:
destructed = -4,
self_move_assigned = -3,
move_assigned_from = -2,
move_constructed_from = -1,
constructed_specified = 0
That is, the special members set the status accordingly. For example ~A() looks like this:
~A()
{
assert(is_valid());
--count;
state_ = randomize();
status_ = destructed;
}
And there's a streaming operator that prints this class out.
Language lawyer disclaimer: Printing out a destructed A is undefined behavior, and anything could happen. That being said, when experiments are compiled with optimizations turned off, you typically get the expected result.
For me, using clang at -O0, this:
#include "A.h"
#include <iostream>
int
main()
{
A a{1};
A b{2};
A c{3};
A&& x = a + b + c;
std::cout << x << '\n';
}
Outputs:
destructed: -1002199219
Changing the line to:
A x = a + b + c;
Results in:
6
Please look at the following code and help me understand:
Why the functionality to return a const alias to a literal like my f2 function exists. I don't understand what the point is.
The difference between f2 and f3 is that const does allow me to put a literal in the return statement, but again why?
Any help in understanding this is appreciated.
#include <iostream>
const int f1(int a)
{
return 15;
}
const int& f2(int a)
{
return 14;
}
int& f3(int a)
{
a = 12;
return a;
}
int main()
{
auto a{ 10 };
auto b = f1(a);
auto c = f2(a);
auto d = f3(a);
std::cout << a << " " << b << " " << c << " " << d << std::endl;
a = 1;
b = 2;
c = 3;
d = 4;
std::cout << a << " " << b << " " << c << " " << d << std::endl;
}
Both f2 and f3 have undefined behaviour. You are returning references to local variables. Those local variables are destroyed when the function ends, and the reference is dangling.
The difference between a const reference, and a non-const reference is that a const reference can bind to both rvalues and lvalues.
For non-const references you have to distinguish between lvalue-reference(int&) and rvalue-reference(int&&).
So using the function signature int&& f2(int a) would also compile, but equally have undefined behaviour.
The main reason this is usefull is because when we pass a reference to a function, the function signature tell us if we are expecting an lvalue or an rvalue. We can also overload both and decide to move/copy depending on what we get.
In the case where we don't care, or if we only want to read from the value we can use a const reference and be able to accept both lvalues and rvalues that are passed in.
void foo(MyClass& mc) {
// We know mc is an lvalue.
// We could copy mc, or modify it if we want to use it as an output parameter.
}
void foo(MyClass&& mc) {
// We know mc is an rvalue.
// We know it would be safe to move from mc in this case.
}
MyClass mc;
foo(mc); // Callsthe first overload
foo(MyClass{}); // Calls the second overload
// The two functions above can be overloaded, so we can make sure we deal
// with both cases in the right way
void foo2(const MyClass& mc) {
// This can be both an rvalue or lvalue.
// We don't really care since the reference
// is const we are only going to read from it.
}
foo2(mc); // Both calls work
foo2(MyClass{});
The b, c and d variables in main are initialized with a copy of what the functions return. No matter if they return a copy, a ref or a const ref.
To keep the attributes of the returned value, let's change the first lines in main:
int main()
{
auto a{ 10 };
auto& b = f1(a); // Does not compile, a ref can't be tied to a r-value
auto& c = f2(a); // Ok, c's type is 'const int&'
auto& d = f3(a); // Ok, d's type is 'int&'
std::cout << a << " " << b << " " << c << " " << d << std::endl;
a = 1;
b = 2;
c = 3; // Does not compile. c is a ref to a const
d = 4;
std::cout << a << " " << b << " " << c << " " << d << std::endl;
}
So, the point is you can return a reference to an internal variable, but now allowing the caller to change it. Doing so (instead of returning a copy), you
avoid the copy
allow the caller to see any later change
Not much sense for the code above, but think of a method inside a class, where the internal variable can be changed in other ways.
Besides the return type, f2 and f3 are not correct, as they return a reference to a not-in-memory (f2) or temporary object (f3).
Let's say you write a function that needs to return a complex object, but this object shouldn't be modified (such as pointer to a shared resource, class-property, some sort a singleton data and so on).
For the sake of this answer, lets assume the type in "struct Point".
You have 2 options to do so:
return it by value, which will create a deep copy of its primitive type members and a shallow copy of its by-reference-types members:
const struct Point f2(...)
return it by reference, which will copy only the pointer to the object:
const struct Point* f2()
const struct Point& f2()
both are valid, while the second one has the advantage when dealing with heavy objects.
In the code you provided you do not see the difference because "int" is a primitive type which means it has known way to be copied. This means var "c" isn't actually an alias nor a const, its an int who took its value from the return type of f2
I was trying some things and came to the following question: Is there a possibility to store references to a value in a std::any?
I tried the following approaches:
#include <any>
#include <iostream>
#include <functional>
auto func_by_pointer(std::any obj)
{
*std::any_cast<int *>(obj) += 2;
}
auto modify_by_pointer(int &a)
{
func_by_pointer(std::make_any<int *>(&a));
}
auto func_by_reference_wrapper(std::any obj)
{
std::any_cast<std::reference_wrapper<int>>(obj).get() -= 2;
}
auto modify_by_reference_wrapper(int &a)
{
func_by_reference_wrapper(std::make_any<std::reference_wrapper<int>>(a));
}
auto func_by_reference(std::any obj)
{
std::any_cast<int &>(obj) *= 2;
}
auto modify_by_reference(int &a)
{
func_by_reference(std::make_any<int &>(a));
}
int main()
{
auto value = 3;
std::cout << value << '\n';
modify_by_pointer(value);
std::cout << value << '\n';
modify_by_reference_wrapper(value);
std::cout << value << '\n';
modify_by_reference(value);
std::cout << value << '\n';
}
The result is the following output:
3
5
3
3
Yet, I was expecting it to be:
3
5
3
6
Thus, passing a pointer to value works fine. Passing a std::reference_wrapper to value works fine as well, but passing int& somehow doesn't work. Did I do something wrong in my code, or is it generally not possible to store references inside a std::any?
You cannot store references in std::any because, for a given type T, the constructor std::any(T) stores a value of type std::decay_t<T>, which removes reference qualifiers:
[any.cons]
template<class T>
any(T&& value);
Let VT be decay_t<T>.
Requires: VT shall satisfy the Cpp17CopyConstructible requirements.
Effects: Constructs an object of type any that contains an object of type VT direct-initialized with std::forward<T>(value).
Reading Meyers new book I found something very similar to this:
// compile with
// g++-4.8 --std=c++11 -Wall main3.cc && ./a.out
#include <iostream>
#include <vector>
class Widget
{
public:
using DType = std::vector<int>;
DType& data() & // lvalue
{
std::cout << "data (lvalue) : " << &data_[0] << std::endl;
return data_;
};
DType data() && // rvalue
{
std::cout << "data (rvalue) : " << &data_[0] << std::endl;
return std::move(data_);
};
// Please Note
// int parameter is here to make the overloading possible
// in a single class
DType&& data(int) &&
{
std::cout << "data (rvalue ref): " << &data_[0] << std::endl;
return std::move(data_);
};
private:
DType data_ { 0 };
};
Widget getWidget() { return Widget(); }
int main(int argc, char *argv[])
{
Widget w1;
std::vector<int> d1 = w1.data();
std::cout << "d1 copied : " << &d1[0] << std::endl;
std::vector<int> d2 = getWidget().data();
std::cout << "d2 moved : " << &d2[0] << std::endl;
std::vector<int> d3 = getWidget().data(0);
std::cout << "d3 moved : " << &d3[0] << std::endl;
return 0;
}
My point is very simple:
On my box as I would expect I have these results
data (lvalue) : 0x8e28008
d1 copied : 0x8e28018
data (rvalue) : 0x8e28028
d2 moved : 0x8e28028
data (rvalue ref): 0x8e28038
d3 moved : 0x8e28038
So first vector was copied while the second and third were moved.
You can have two different signature to achieve move operation:
One returning an rvalue
DType data() && // rvalue
and one returing a rvalue reference
DType&& data() &&
They achieve the same result: are there any differences I cannot see ? What is the "best" one?
You can have two different signature to achieve move operation:
That is wrong.
The first signature, the one returning DType, performs a move into the return value. The second signature, the one returning DType&& simply returns a reference. It doesn't move anything.
The move happens in the other code, specifically the part with std::vector<int> d3 =. Initializing a vector from an xvalue performs a move. That is what does the move, not the function. However, other kinds of operations won't perform a move:
// no move, just binding the member to a reference
std::vector<int>&& d3 = getWidget().data(0);
Using the first function, however, the move always happens:
// move into a temporary, and bind *that* to a reference
std::vector<int>&& d2 = getWidget().data();
The second signature is dangerous. It is easy to accidentally return a reference to a temporary with it. It is easy to write misleading client code where you think something got moved out but didn't. There is one sensible use case for returning rvalue references, and that use case was already taken care of by the standard library in the forms of std::move and std::forward.
I was just reading this
class biggerThan
{
public:
const int testValue;
biggerThan(int x) : testValue(x) { }
bool operator()(int val) const
{ return val > testValue; }
};
Now say its used like
std::list<int>::iterator firstBig =
std::find_if(aList.begin(), aList.end(), biggerThan(12));
OR
Just simply like this
biggerThan object(12)
Now when biggerThan(12) this is used it can invoke the constrcutor to initialze the testvalue or () operator is overloaded and 12 is passed to the function(bool operator()(int val) const ) so that it returns a bool.
which one happens first/how does it works
does it leads to any ambiguity or does the call to the overlaode operator happens in some fashion like
object.operator().(12).
please make my undersatnding clear.
Maybe the following code will make it clear:
#include <iostream>
#include <algorithm>
class biggerThan
{
public:
const int testValue;
biggerThan(int x) : testValue(x) {
std::cout << "Construction of biggerThan object with value "
<< x << std::endl;
}
bool operator()(int val) const
{
if (val > testValue) {
std::cout << val << " is bigger than " << testValue
<< std::endl;
return true;
}
else {
std::cout << val << " is *not* bigger than " << testValue
<< std::endl;
return false;
}
}
};
int main() {
int data[] = {0,1,2,3,4,5,6,7,8,9};
std::for_each(data, data+10, biggerThan(4));
}
The output is:
Construction of biggerThan object with value 4
0 is *not* bigger than 4
1 is *not* bigger than 4
2 is *not* bigger than 4
3 is *not* bigger than 4
4 is *not* bigger than 4
5 is bigger than 4
6 is bigger than 4
7 is bigger than 4
8 is bigger than 4
9 is bigger than 4
What happens:
The last argument to std::for_each is an object of type biggerThan, that is constructed with the argument 4.
The operator()(int) of this biggerThan-object (actually a copy of it) is invoked for every element in data.
The algorithm you use (std::find_if) works the same in this regard.
when biggerThan(12) this is used it can invoke the constructor to initialize the testvalue
Yes. biggerThan(12) creates an instance of the biggerThan class with testvalue set to 12.
When std::find_if() calls the functor, it will call the operator()(int val) member function of that instance.
biggerThan(12) will pass an object of biggerThan at std::find_if(aList.begin(), aList.end(), biggerThan(12)); line;
To invoke operator() following is the way;
biggerThan obj(12); //This is a constructor call
biggerThan(13); //This is function operator call
#std::find_if(aList.begin(), aList.end(), biggerThan(12)); the third parameter that is passed will be temporary object of biggerThan initialized with 12
In general, you can accomplish the same thing using greater<> and bind2nd<>, which are in <functional>
list<int>::iterator firstBig = find_if(aList.begin(), aList.end,
bind2nd(greater<int>(), 12));
bind2nd turns any binary function object, like greater<int> into a unary function object. In the case of greater<int> it effectively creates a function object whose less than operator looks like this
bool operator>(const int& arg)
{
return functor.operator>(arg, 12);
}
where functor is greater<int>