When running the following code, which involves changing the value of a int via a method of a class called B, which inherits from a templated class A, the value of the int doesn't change, and I cannot understand why, I have tested both of these with clang trunk and gcc trunk:
#include <iostream>
template<typename T>
struct A
{
A(T& a_num_) : a_num(a_num_) {}
T& a_num;
};
struct B : public A<int>
{
template<typename... Args>
B(Args... args) : A<int>(args...) {}
void do_something()
{
a_num = 1634;
}
};
int main(void)
{
int num = 4;
B b {num};
b.do_something();
std::cout << num;
return 0;
}
I would expect to get 1634 printed, but instead 4 prints.
I have narrowed the error to the constructor of B, because if I change the constructor of B to be:
B(int& x) : A<int>(x) {}
then the correct value appears, but the current constructor should also be receiving an int, because when I type:
B b {num};
Then it should choose Args = [int&], because that's the only way to satisfy A's constructor, which takes a T&, so what is happening here? What is a_num in this case? Just a garbage reference that doesn't reference anything, or possibly a temporary object?
I've also tried to rewrite the do_something function as
A<int>::a_num = 1634
but it still doesn't manage to change it.
I've also noticed that declaring b as:
B b {6};
Also works, although there's no way 6, which is a pr-value, could bind to a l-value reference.
So my question here is why does B's constructor choose Args = [int] instead of Args = [int&] and how can it do this when it then passes that Args to a constructor that takes a T&?
The only time a template type parameter will be deduced to be a reference type is when you declare the corresponding function parameter to be T&& and pass an lvalue to the function.
That means in this case Args is deduced to be {int}. After B's constructor is instantiated, it looks like this:
B(int arg) : A<int>(arg) {}
This is perfectly valid, because arg is an lvalue, and so the a_num_ parameter to A's constructor can bind to it. You then copy that reference to the A's a_num member and then the function parameter it's bound to goes out of scope and a_num becomes a dangling reference. The behavior when you attempt to assign through a_num is therefore undefined.
If you want B's constructor to take its arguments by reference, then you need to define the argument's type to be a reference:
tmeplate <typename... Args>
B(Args&... args) : A<int>(args) {}
If you do that then b.a_num will be a reference to the num you defined in main and everything will work like you expect.
You should change B's constructor to take Args as a reference Args&...:
template<typename... Args>
B(Args&... args) : A<int>(args...) {}
Now your code will print 1634 as you originally wanted.
Confirming the memory addresses
If you want to confirm that those variables point to the same memory address, you can do:
std::cout << &num << '\n';
std::cout << &b.a_num << '\n';
This prints the same memory address. For example:
0x7fff5508cac8
0x7fff5508cac8
Using pointers
Since the idea is to make both num and A::a_num point to the same memory address, it is worth mentioning a solution that uses pointers. In that case, you don't have to change B's constructor, but you have to change A::a_num to be a T*.
template<typename T>
struct A
{
A(T* a_num_) : a_num(a_num_) {}
T* a_num;
};
struct B : public A<int>
{
template<typename... Args>
B(Args... args) : A<int>(args...) {}
void do_something() {
*a_num = 1634;
}
};
int main(void)
{
int num = 4;
B b {&num};
b.do_something();
std::cout << num;
}
This code also prints 1634 as you originally wanted.
Edit: I should remember that this code is bad practice and should never be recommended for production use. The memory address of local variables should never be passed around since they are only valid while the scope exists in the stack. We can implement much better code by using smart pointers or simply by copying the values instead of reusing their memory addresses.
Related
Here I declared two template classes: A and B, B derives from A:
template<typename T>
class A {
public:
int a;
T t;
};
template<typename T>
class B : public A<T> {
public:
int b;
};
And I make a shared_ptr<B<T>> and assign it to shared_ptr<A<T>>, it's ok:
auto b = std::make_shared<B<std::string>>();
std::shared_ptr<A<std::string>> a = b;
Here I declared a template function accept shared_ptr A<T>:
template<typename T>
void proc(std::shared_ptr<A<T>> &a) {
std::cout << a->a << std::endl;
}
it accepts a as argument, but rejects b:
proc<std::string>(a); // OK
proc<std::string>(b); // template argument deduction/substitution failed
// cannot convert 'b' (type 'std::shared_ptr<B<std::__cxx11::basic_string<char> > >') to type 'std::shared_ptr<A<std::__cxx11::basic_string<char> > >&'
I use g++ as compiler with -std=c++11.
This error brings me a lot problems and how could I fix this elegantly?
Given proc<std::string>(b);, b needs to be converted to std::shared_ptr<A<std::string>>. That means a temporary std::shared_ptr<A<std::string>> will be constructed and then passed to proc. The parameter type of proc is an lvalue-reference to non-const, i.e. std::shared_ptr<A<T>> &, which can't bind to temporaries.
You can change the parameter type to lvalue-reference to const, which could bind to temporaries. e.g.
template<typename T>
void proc(const std::shared_ptr<A<T>> &a) {
// ^^^^^
std::cout << a->a << std::endl;
}
First of all, you make a shared_ptr called:
auto b = std::make_shared<B<std::string>>();
Is of type std::shared_ptr<B<std::string>> and,
std::shared_ptr<A<std::string>> a = b;
Is of type std::shared_ptr<A<std::string>>...
In your function parameter, however, you have:
void proc(std::shared_ptr<A<T>> &a)
Which only points to the shared_ptr of A, not B, so it is obvious that B won't become A...
The solution would be to remove the lvalue reference of a from the function definition, like:
void proc(std::shared_ptr<A<T>> a)
so, it doesn't refer to A, and B can easily be converted to A during function call...
Edit: Added an explanation...
Explanation:
Remember pointers? from C... yes, they do the same function of references:
// Compilable both in C and C++...
int add(int a, int b, int * more_than_3) {
int const result = a + b;
if (result > 3)
*more_than_3 = 1;
return result;
}
Yeah, these which would the function of pseudo-return types in C. Like:
// Compilable both in C and C++...
int main(void) {
int more_3;
int const res = add(2, 3, &more_3);
printf("Sum of 2 + 3 is %i\n", res);
if (more_3)
printf("Given two numbers' sum is more than 3");
}
Here, an extra argument is passed which takes the address of a variable (References also do the same thing, they share their address with the variable with whom they are referenced...)
Remember, references and pointers store the address of another variable inside of them...
This might be the reason why they made the address of operator (&) also act for references in C++...
Also, unneeded, but the answer which was posted here by #songyuanyao worked, because:
void proc(std::shared_ptr<A<T>> const &a)
uses a constant reference, a reference to a constant expression, not a variable, so it didn't matter if they mismatched (A and B)
I wrote some code S s; ... s = {};, expecting it to end up the same as S s = {};. However it didn't. The following example reproduces the problem:
#include <iostream>
struct S
{
S(): a(5) { }
S(int t): a(t) {}
S &operator=(int t) { a = t; return *this; }
S &operator=(S const &t) = default;
int a;
};
int main()
{
S s = {};
S t;
t = {};
std::cout << s.a << '\n';
std::cout << t.a << '\n';
}
The output is:
5
0
My questions are:
Why is operator=(int) selected here, instead of "ambiguous" or the other one?
Is there a tidy workaround, without changing S?
My intent is s = S{}; . Writing s = {}; would be convenient if it worked. I'm currently using s = decltype(s){}; however I'd prefer to avoid repeating the type or the variable name.
Why is operator=(int) selected here, instead of "ambiguous" or the other one?
{} to int is the identity conversion ([over.ics.list]/9). {} to S is a user-defined conversion ([over.ics.list]/6) (technically, it's {} to const S&, and goes through [over.ics.list]/8 and [over.ics.ref] first before coming back to [over.ics.list]/6).
The first wins.
Is there a tidy workaround?
A variation of the trick std::experimental::optional pulls to make t = {} always make t empty.
The key is to make operator=(int) a template. If you want to accept int and only int, then it becomes
template<class Int, std::enable_if_t<std::is_same<Int, int>{}, int> = 0>
S& operator=(Int t) { a = t; return *this; }
Different constraints can be used if you want to enable conversions (you'd probably also want to take the argument by reference in that case).
The point is that by making the right operand's type a template parameter, you block t = {} from using this overload - because {} is a non-deduced context.
...without changing S?
Does template<class T> T default_constructed_instance_of(const T&) { return {}; } and then s = default_constructed_instance_of(s);count?
First of all, the case has nothing to do with the "int" version of the assignment operator, you can just delete it. You can actually delete the other assignment operator too as it will be generated by the compiler. IE this kind of type automatically receives copy/move constructors and the assignment operator. (ie they are not prohibited and you are just repeating what the compiler does automatically with explicit notation)
The first case
uses copy initialization:
S s = {}; // the default constructor is invoked
That is a post-construction copy assignment, yet compilers optimize such simple cases. You should use direction initialization instead:
S s{}; // the default constructor is invoked (as you have it)
Note, you can also write:
S s; // the default constructor is invoked if you have it
The second case
What you should write is direct initialization of the right hand side of the copy assignment:
t = S{};
This notation will invoke the default constructor (if there is one), or value initialization for the members (as long as the type is an aggregate). Here is the relevant info: http://en.cppreference.com/w/cpp/language/value_initialization
I have a class with copy & move ctor deleted.
struct A
{
A(int a):data(a){}
~A(){ std::cout << "~A()" << this << " : " << data << std::endl; }
A(A const &obj) = delete;
A(A &&obj) = delete;
friend std::ostream & operator << ( std::ostream & out , A const & obj);
int data;
};
And I want to create a tuple with objects of this class. But the following does not compile:
auto p = std::tuple<A,A>(A{10},A{20});
On the other hand, the following does compile, but gives a surprising output.
int main() {
auto q = std::tuple<A&&,A&&>(A{100},A{200});
std::cout << "q created\n";
}
Output
~A()0x22fe10 : 100
~A()0x22fe30 : 200
q created
It means that dtor for objects is called as soon as tuple construction line ends. So, what is significance of a tuple of destroyed objects?
This is bad:
auto q = std::tuple<A&&,A&&>(A{100},A{200});
you are constructing a tuple of rvalue references to temporaries that get destroyed at the end of the expression, so you're left with dangling references.
The correct statement would be:
std::tuple<A, A> q(100, 200);
However, until quite recently, the above was not supported by the standard. In N4296, the wording around the relevant constructor for tuple is [tuple.cnstr]:
template <class... UTypes>
constexpr explicit tuple(UTypes&&... u);
Requires: sizeof...(Types) == sizeof...(UTypes). is_constructible<Ti, Ui&&>::value is true
for all i.
Effects: Initializes the elements in the tuple with the corresponding value in std::forward<UTypes>(u).
Remark: This constructor shall not participate in overload resolution unless each type in UTypes is
implicitly convertible to its corresponding type in Types.
So, this constructor was not participating in overload resolution because int is not implicitly convertible to A. This has been resolved by the adoption of Improving pair and tuple, which addressed precisely your use-case:
struct D { D(int); D(const D&) = delete; };
std::tuple<D> td(12); // Error
The new wording for this constructor is, from N4527:
Remarks: This constructor shall not participate in overload resolution unless sizeof...(Types) >= 1 and is_constructible<Ti, Ui&&>::value is true for all i. The constructor is explicit if and only
if is_convertible<Ui&&, Ti>::value is false for at least one i.
And is_constructible<A, int&&>::value is true.
To present the difference another way, here is an extremely stripped down tuple implementation:
struct D { D(int ) {} D(const D& ) = delete; };
template <typename T>
struct Tuple {
Tuple(const T& t)
: T(t)
{ }
template <typename U,
#ifdef USE_OLD_RULES
typename = std::enable_if_t<std::is_convertible<U, T>::value>
#else
typename = std::enable_if_t<std::is_constructible<T, U&&>::value>
#endif
>
Tuple(U&& u)
: t(std::forward<U>(u))
{ }
T t;
};
int main()
{
Tuple<D> t(12);
}
If USE_OLD_RULES is defined, the first constructor is the only viable constructor and hence the code will not compile since D is noncopyable. Otherwise, the second constructor is the best viable candidate and that one is well-formed.
The adoption was recent enough that neither gcc 5.2 nor clang 3.6 actually will compile this example yet. So you will either need a newer compiler than that (gcc 6.0 works) or come up with a different design.
Your problem is that you explicitly asked for a tuple of rvalue references, and a rvalue reference is not that far from a pointer.
So auto q = std::tuple<A&&,A&&>(A{100},A{200}); creates two A objects, takes (rvalue) references to them, build the tuple with the references... and destroys the temporary objects, leaving you with two dangling references
Even if it is said to be more secure than good old C and its dangling pointers, C++ still allows programmer to write wrong programs.
Anyway, the following would make sense (note usage of A& and not A&&):
int main() {
A a(100), b(100); // Ok, a and b will leave as long as main
auto q = tuple<A&, A&>(a, b); // ok, q contains references to a and b
...
return 0; // Ok, q, a and b will be destroyed
}
Imagine you have a number of overloaded methods that (before C++11) looked like this:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
};
This function makes a copy of a (MyBigType), so I want to add an optimization by providing a version of f that moves a instead of copying it.
My problem is that now the number of f overloads will duplicate:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
void f(MyBigType&& a, int id);
void f(MyBigType&& a, string name);
void f(MyBigType&& a, int b, int c, int d);
// ...
};
If I had more parameters that could be moved, it would be unpractical to provide all the overloads.
Has anyone dealt with this issue? Is there a good solution/pattern to solve this problem?
Thanks!
Herb Sutter talks about something similar in a cppcon talk
This can be done but probably shouldn't. You can get the effect out using universal references and templates, but you want to constrain the type to MyBigType and things that are implicitly convertible to MyBigType. With some tmp tricks, you can do this:
class MyClass {
public:
template <typename T>
typename std::enable_if<std::is_convertible<T, MyBigType>::value, void>::type
f(T&& a, int id);
};
The only template parameter will match against the actual type of the parameter, the enable_if return type disallows incompatible types. I'll take it apart piece by piece
std::is_convertible<T, MyBigType>::value
This compile time expression will evaluate to true if T can be converted implicitly to a MyBigType. For example, if MyBigType were a std::string and T were a char* the expression would be true, but if T were an int it would be false.
typename std::enable_if<..., void>::type // where the ... is the above
this expression will result in void in the case that the is_convertible expression is true. When it's false, the expression will be malformed, so the template will be thrown out.
Inside the body of the function you'll need to use perfect forwarding, if you are planning on copy assigning or move assigning, the body would be something like
{
this->a_ = std::forward<T>(a);
}
Here's a coliru live example with a using MyBigType = std::string. As Herb says, this function can't be virtual and must be implemented in the header. The error messages you get from calling with a wrong type will be pretty rough compared to the non-templated overloads.
Thanks to Barry's comment for this suggestion, to reduce repetition, it's probably a good idea to create a template alias for the SFINAE mechanism. If you declare in your class
template <typename T>
using EnableIfIsMyBigType = typename std::enable_if<std::is_convertible<T, MyBigType>::value, void>::type;
then you could reduce the declarations to
template <typename T>
EnableIfIsMyBigType<T>
f(T&& a, int id);
However, this assumes all of your overloads have a void return type. If the return type differs you could use a two-argument alias instead
template <typename T, typename R>
using EnableIfIsMyBigType = typename std::enable_if<std::is_convertible<T, MyBigType>::value,R>::type;
Then declare with the return type specified
template <typename T>
EnableIfIsMyBigType<T, void> // void is the return type
f(T&& a, int id);
The slightly slower option is to take the argument by value. If you do
class MyClass {
public:
void f(MyBigType a, int id) {
this->a_ = std::move(a); // move assignment
}
};
In the case where f is passed an lvalue, it will copy construct a from its argument, then move assign it into this->a_. In the case that f is passed an rvalue, it will move construct a from the argument and then move assign. A live example of this behavior is here. Note that I use -fno-elide-constructors, without that flag, the rvalue cases elides the move construction and only the move assignment takes place.
If the object is expensive to move (std::array for example) this approach will be noticeably slower than the super-optimized first version. Also, consider watching this part of Herb's talk that Chris Drew links to in the comments to understand when it could be slower than using references. If you have a copy of Effective Modern C++ by Scott Meyers, he discusses the ups and downs in item 41.
You may do something like the following.
class MyClass {
public:
void f(MyBigType a, int id) { this->a = std::move(a); /*...*/ }
void f(MyBigType a, string name);
void f(MyBigType a, int b, int c, int d);
// ...
};
You just have an extra move (which may be optimized).
My first thought is that you should change the parameters to pass by value. This covers the existing need to copy, except the copy happens at the call point rather than explicitly in the function. It also allows the parameters to be created by move construction in a move-able context (either unnamed temporaries or by using std::move).
Why you would do that
These extra overloads only make sense, if modifying the function paramers in the implementation of the function really gives you a signigicant performance gain (or some kind of guarantee). This is hardly ever the case except for the case of constructors or assignment operators. Therefore, I would advise you to rethink, whether putting these overloads there is really necessary.
If the implementations are almost identical...
From my experience this modification is simply passing the parameter to another function wrapped in std::move() and the rest of the function is identical to the const & version. In that case you might turn your function into a template of this kind:
template <typename T> void f(T && a, int id);
Then in the function implementation you just replace the std::move(a) operation with std::forward<T>(a) and it should work. You can constrain the parameter type T with std::enable_if, if you like.
In the const ref case: Don't create a temporary, just to to modify it
If in the case of constant references you create a copy of your parameter and then continue the same way the move version works, then you may as well just pass the parameter by value and use the same implementation you used for the move version.
void f( MyBigData a, int id );
This will usually give you the same performance in both cases and you only need one overload and implementation. Lots of plusses!
Significantly different implementations
In case the two implementations differ significantly, there is no generic solution as far as I know. And I believe there can be none. This is also the only case, where doing this really makes sense, if profiling the performance shows you adequate improvements.
You might introduce a mutable object:
#include <memory>
#include <type_traits>
// Mutable
// =======
template <typename T>
class Mutable
{
public:
Mutable(const T& value) : m_ptr(new(m_storage) T(value)) {}
Mutable(T& value) : m_ptr(&value) {}
Mutable(T&& value) : m_ptr(new(m_storage) T(std::move(value))) {}
~Mutable() {
auto storage = reinterpret_cast<T*>(m_storage);
if(m_ptr == storage)
m_ptr->~T();
}
Mutable(const Mutable&) = delete;
Mutable& operator = (const Mutable&) = delete;
const T* operator -> () const { return m_ptr; }
T* operator -> () { return m_ptr; }
const T& operator * () const { return *m_ptr; }
T& operator * () { return *m_ptr; }
private:
T* m_ptr;
char m_storage[sizeof(T)];
};
// Usage
// =====
#include <iostream>
struct X
{
int value = 0;
X() { std::cout << "default\n"; }
X(const X&) { std::cout << "copy\n"; }
X(X&&) { std::cout << "move\n"; }
X& operator = (const X&) { std::cout << "assign copy\n"; return *this; }
X& operator = (X&&) { std::cout << "assign move\n"; return *this; }
~X() { std::cout << "destruct " << value << "\n"; }
};
X make_x() { return X(); }
void fn(Mutable<X>&& x) {
x->value = 1;
}
int main()
{
const X x0;
std::cout << "0:\n";
fn(x0);
std::cout << "1:\n";
X x1;
fn(x1);
std::cout << "2:\n";
fn(make_x());
std::cout << "End\n";
}
This is the critical part of the question:
This function makes a copy of a (MyBigType),
Unfortunately, it is a little ambiguous. We would like to know what is the ultimate target of the data in the parameter. Is it:
1) to be assigned to an object that existing before f was called?
2) or instead, stored in a local variable:
i.e:
void f(??? a, int id) {
this->x = ??? a ???;
...
}
or
void f(??? a, int id) {
MyBigType a_copy = ??? a ???;
...
}
Sometimes, the first version (the assignment) can be done without any copies or moves. If this->x is already long string, and if a is short, then it can efficiently reuse the existing capacity. No copy-construction, and no moves. In short, sometimes assignment can be faster because we can skip the copy contruction.
Anyway, here goes:
template<typename T>
void f(T&& a, int id) {
this->x = std::forward<T>(a); // is assigning
MyBigType local = std::forward<T>(a); // if move/copy constructing
}
If the move version will provide any optimization then the implementation of the move overloaded function and the copy one must be really different. I don't see a way to get around this without providing implementations for both.
I am having trouble understanding why the lifetime of temporaries bound to const reference parameters is cut short when there is a perfect forwarding constructor around. First of, what we know about temporaries bound to reference parameters: they last for the full expression:
A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full expression containing the call
However I found cases where this is not true (or I might simply misunderstand what a full expression is). Let's take a simple example, first we define an object with verbose constructors and destructors:
struct A {
A(int &&) { cout << "create A" << endl; }
A(A&&) { cout << "move A" << endl; }
~A(){ cout << "kill A" << endl; }
};
And an object wrapper B, which will be used for reference collapsing:
template <class T> struct B {
T value;
B() : value() { cout << "new B" << endl; }
B(const T &__a) : value(__a) { cout << "create B" << endl; }
B(const B &p) = default;
B(B && o) = default;
~B(){ cout << "kill B" << endl; };
};
We can now use our wrapper to capture references on temporaries and use them in function calls, like so:
void foo(B<const A&> a){ cout << "Using A" << endl; }
int main(){ foo( {123} ); }
The program above prints what I would expect:
create A
create B
Using A
kill B
kill A
So far so good. Now let's move back to B and add a perfect forwarding constructor for convertible types:
template <class T> struct B {
/* ... */
template <class U, class = typename enable_if<is_convertible<U, T>::value>::type>
B(U &&v) : value(std::forward<U>(v)) {
cout << "new forward initialized B" << endl;
}
};
Compiling the same code again now gives:
create A
new forward initialized B
kill A
Using A
kill B
Note that our A object was now killed before it was used, which is bad! Why did the lifetime of the temporary not get extended to the full call of foo in this case? Also, there is no other call to the desctructor of A, so there is no other instance of it.
I can see two possible explanations:
either the types are not what I think they are: changing the convertible move constructor to B(T &&v) instead of template <class U>B(U &&v) solves the problem.
or {123} is not a subexpression of foo( {123} ). Swapping {123} for A(123) also solves the issue, which makes me wonder if brace-initializers are full expressions.
Could someone clarify what is going on here?
Does this mean that adding a forwarding constructor to a class could break backward compatibility in some cases, like it did for B?
You can find the full code here, with another test case crashing for references to strings.
The type inferred for U in the call to B<A const&>::B(U&&) is int, so the only temporary that can be lifetime-extended for the call to foo in main is a prvalue int temporary initialized to 123.
The member A const& value is bound to a temporary A, but that A is created in the mem-initializer-list of the constructor B<A const&>::B(U&&) so its lifetime is extended only for the duration of that member initialization [class.temporary]/5:
— A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits.
Note that a mem-initializer-list is the part after the colon in a ctor-initializer:
template <class U, class = typename enable_if<is_convertible<U, T>::value>::type>
B(U &&v) : value(std::forward<U>(v)) {
^--- ctor-initializer
^--- reference member
^--- temporary A
This is why kill A is printed after new forward initialized B.
Does this mean that adding a forwarding constructor to a class could break backward compatibility in some cases, like it did for B?
Yes. In this case it's difficult to see why the forwarding constructor would be necessary; it's certainly dangerous where you have a reference member that a temporary could be bound to.
void foo(B<const A&> b);
foo( {123} );
is semantically equivalent to:
B<const A&> b = {123};
that for a non-explicit constructor is semantically equivalent to:
B<const A&> b{123};
going further, since your forwarding-constructor takes anything, it actually is initialized with int, not A:
B<const A&>::B(int&& v)
That is, a temporary instance of A is created on the constructor's initialization list:
B(int&& v) : value(A{v}) {}
// created here ^ ^ destroyed here
which is legal, just like you can type const A& a{123};.
This A instance is destroyed after the B's construction is finished, and you end up with a dangling reference within the body of foo.
The situation changes when you build the instance in a call expression, then the A temporary ends its lifetime at the end of the call expression:
foo( A{123} );
// ^ A is destroyed here
so it stays alive within foo, and the forwarding-constructor selected for B<const A&> is instantiated with a type A&&.