I have the following Code
#include <iostream>
template<typename T>
struct A
{
T e_;
A(T e) : e_(e)
{
std::cout<<"A\n";
}
A(const A& other)
{
std::cout<<" ACopy\n";
}
~A() { std::cout<<"~A\n";}
};
struct B
{
B() { std::cout<< "B\n";}
};
int main()
{
A a(A(A(B{})));
return 0;
}
I am not sure why A is being constructed only once.
here is a godbolt link https://godbolt.org/z/fsvzTf
This is because of copy elision. You can read more about it on https://en.cppreference.com/w/cpp/language/copy_elision.
BTW, this leads to other surprising effects as in Why does an object returned by value have the same address as the object inside the method?.
Related
Here is the problem I was thinking about lately. Let's say our interface is a member function that returns object which is expensive to copy and cheap to move (std::string, std::vector, et cetera). Some implementations may compute the result and return a temporary object while others may simply return a member object.
Sample code to illustrate:
// assume the interface is: Vec foo() const
// Vec is cheap to move but expensive to copy
struct RetMember {
Vec foo() const { return m_data; }
Vec m_data;
// some other code
}
struct RetLocal {
Vec foo() const {
Vec local = /*some computation*/;
return local;
}
};
There are also various "clients". Some only read the data, some require an ownership.
void only_reads(const Vec&) { /* some code */ }
void requires_ownership(Vec) { /* some code */ }
Code above composes well, but is not as efficient as it could be. Here are all combinations:
RetMember retmem;
RetLocal retloc;
only_reads(retmem.foo()); // unnecessary copy, bad
only_reads(retloc.foo()); // no copy, good
requires_ownership(retmem.foo()); // copy, good
requires_ownership(retloc.foo()); // no copy, good
What is a good way to fix this situation?
I came up with two ways, but I'm sure there is a better solution.
In my first attempt I wrote a DelayedCopy wrapper that holds either a value of T or a pointer to const T. It is very ugly, requires extra effort, introduces redundant moves, gets in the way of copy elision and probably has many other problems.
My second thought was a continuation-passing style, which works quite well but turns member functions into member function templates. I know, there is std::function, but it has its overhead so performance-wise it may be unacceptable.
Sample code:
#include <boost/variant/variant.hpp>
#include <cstdio>
#include <iostream>
#include <type_traits>
struct Noisy {
Noisy() = default;
Noisy(const Noisy &) { std::puts("Noisy: copy ctor"); }
Noisy(Noisy &&) { std::puts("Noisy: move ctor"); }
Noisy &operator=(const Noisy &) {
std::puts("Noisy: copy assign");
return *this;
}
Noisy &operator=(Noisy &&) {
std::puts("Noisy: move assign");
return *this;
}
};
template <typename T> struct Borrowed {
explicit Borrowed(const T *ptr) : data_(ptr) {}
const T *get() const { return data_; }
private:
const T *data_;
};
template <typename T> struct DelayedCopy {
private:
using Ptr = Borrowed<T>;
boost::variant<Ptr, T> data_;
static_assert(std::is_move_constructible<T>::value, "");
static_assert(std::is_copy_constructible<T>::value, "");
public:
DelayedCopy() = delete;
DelayedCopy(const DelayedCopy &) = delete;
DelayedCopy &operator=(const DelayedCopy &) = delete;
DelayedCopy(DelayedCopy &&) = default;
DelayedCopy &operator=(DelayedCopy &&) = default;
DelayedCopy(T &&value) : data_(std::move(value)) {}
DelayedCopy(const T &cref) : data_(Borrowed<T>(&cref)) {}
const T &ref() const { return boost::apply_visitor(RefVisitor(), data_); }
friend T take_ownership(DelayedCopy &&cow) {
return boost::apply_visitor(TakeOwnershipVisitor(), cow.data_);
}
private:
struct RefVisitor : public boost::static_visitor<const T &> {
const T &operator()(Borrowed<T> ptr) const { return *ptr.get(); }
const T &operator()(const T &ref) const { return ref; }
};
struct TakeOwnershipVisitor : public boost::static_visitor<T> {
T operator()(Borrowed<T> ptr) const { return T(*ptr.get()); }
T operator()(T &ref) const { return T(std::move(ref)); }
};
};
struct Bar {
Noisy data_;
auto fl() -> DelayedCopy<Noisy> { return Noisy(); }
auto fm() -> DelayedCopy<Noisy> { return data_; }
template <typename Fn> void cpsl(Fn fn) { fn(Noisy()); }
template <typename Fn> void cpsm(Fn fn) { fn(data_); }
};
static void client_observes(const Noisy &) { std::puts(__func__); }
static void client_requires_ownership(Noisy) { std::puts(__func__); }
int main() {
Bar a;
std::puts("DelayedCopy:");
auto afl = a.fl();
auto afm = a.fm();
client_observes(afl.ref());
client_observes(afm.ref());
client_requires_ownership(take_ownership(a.fl()));
client_requires_ownership(take_ownership(a.fm()));
std::puts("\nCPS:");
a.cpsl(client_observes);
a.cpsm(client_observes);
a.cpsl(client_requires_ownership);
a.cpsm(client_requires_ownership);
}
Output:
DelayedCopy:
Noisy: move ctor
client_observes
client_observes
Noisy: move ctor
Noisy: move ctor
client_requires_ownership
Noisy: copy ctor
client_requires_ownership
CPS:
client_observes
client_observes
client_requires_ownership
Noisy: copy ctor
client_requires_ownership
Are there better techniques to pass values that avoid extra copies yet are still general (allow returning both temporaries and data members)?
On a side note: the code was compiled with g++ 5.2 and clang 3.7 in C++11. In C++14 and C++1z DelayedCopy doesn't compile and I'm not sure whether it's my fault or not.
There are probably thousands of 'correct' ways. I would favour one in which:
the the method that delivers the reference or moved object is explicitly stated so no-one is in any doubt.
as little code to maintain as possible.
all code combination compile and do sensible things.
something like this (contrived) example:
#include <iostream>
#include <string>
#include <boost/optional.hpp>
// an object that produces (for example) strings
struct universal_producer
{
void produce(std::string s)
{
_current = std::move(s);
// perhaps signal clients that there is something to take here?
}
// allows a consumer to see the string but does not relinquish ownership
const std::string& peek() const {
// will throw an exception if there is nothing to take
return _current.value();
}
// removes the string from the producer and hands it to the consumer
std::string take() // not const
{
std::string result = std::move(_current.value());
_current = boost::none;
return result;
}
boost::optional<std::string> _current;
};
using namespace std;
// prints a string by reference
void say_reference(const std::string& s)
{
cout << s << endl;
}
// prints a string after taking ownership or a copy depending on the call context
void say_copy(std::string s)
{
cout << s << endl;
}
auto main() -> int
{
universal_producer producer;
producer.produce("Hello, World!");
// print by reference
say_reference(producer.peek());
// print a copy but don't take ownership
say_copy(producer.peek());
// take ownership and print
say_copy(producer.take());
// producer now has no string. next peek or take will cause an exception
try {
say_reference(producer.peek());
}
catch(const std::exception& e)
{
cout << "exception: " << e.what() << endl;
}
return 0;
}
expected output:
Hello, World!
Hello, World!
Hello, World!
exception: Attempted to access the value of an uninitialized optional object.
I have a type hierarchy similar to the code sample below, and I'm trying to instantiate them via the factory pattern (or, to be pedantic, rather the builder pattern, as my factory takes input from an XML document... but I digress).
However I try to do this, I'm running into problems which I suspect are due to either slicing, if I return by value, or to scoping, if I return by reference.
The below program, for instance, segfaults on the line a.doA() inside C::doStuff(). If I change the call to value_C_factory<C>() to ref_C_factory<C>() instead, I get a couple of warnings to the effect of "returning reference to temporary", but the program compiles, segfaults instead on b.doB() on the next line (without having printed anything from a.doA()...).
The backtrace from gdb looks like this - the second line is the one in my code referred to above
#0 0x00007ffff7dbddb0 in vtable for std::ctype<char> () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00000000004010e9 in C::doStuff (this=0x7fffffffdd00) at syntax.cpp:57
#2 0x0000000000400cf2 in main () at syntax.cpp:95
What is causing these segfaults? Is it, as I suspect, slicing/scoping in the value/reference case? If not, what is it? And most importantly, what is a good way to build my instances from the input data?
Code sample
The code below should compile and give the above behavior with e.g. GCC 4.8, using
gcc -g -Wall -std=c++11 -o test test.cpp (that's what I do, anyway).
#include <iostream>
#include <typeinfo>
class IA {
public:
virtual void doA() const = 0;
virtual ~IA() { }
};
class A : public IA {
private:
std::string atask;
public:
explicit A(const std::string &task) : atask(task) {
std::cout << "Created A with task " << atask << std::endl;
}
void doA() const {
std::cout << "I did A! " << atask << std::endl;
}
};
class IB {
public:
virtual void doB() const = 0;
virtual ~IB() { }
};
class B : public IB {
private:
std::string btask;
public:
explicit B(const std::string &task) : btask(task) {
std::cout << "Created B with task " << btask << std::endl;
}
void doB() const {
std::cout << "I did B! " << btask << std::endl;
}
};
class IC {
public:
void doStuff() const;
virtual ~IC() { }
};
class C : public IC {
private:
const IA &a;
const IB &b;
public:
C(const IA &a, const IB &b) : a(a), b(b) { }
void doStuff() const {
a.doA(); // with value factory method, segfault here
b.doB(); // with reference factory, segfault here instead
}
};
template<typename TA>
TA value_A_factory() {
return TA("a value");
}
template<typename TB>
TB value_B_factory() {
return TB("b value");
}
template<typename TC>
TC value_C_factory() {
return TC(value_A_factory<A>(), value_B_factory<B>());
}
template<typename TA>
const TA &ref_A_factory() {
return TA("a ref");
}
template<typename TB>
const TB &ref_B_factory() {
return TB("b ref");
}
template<typename TC>
const TC &ref_C_factory() {
const TC &c(ref_A_factory<A>(), ref_B_factory<B>());
return c;
}
int main() {
C c = value_C_factory<C>();
std::cout << typeid(c).name() << std::endl;
c.doStuff();
}
You have two problems, both caused by undefined behavior.
The first is that you can't return a reference to a local variable. Once the function returns and the local variable goes out of scope and is destructed, what does the returned reference then reference?
The other problem is that you store references to temporary values. When you create your C class like TC(value_A_factory<A>(), value_B_factory<B>()) the values returned by the value_X_factory functions are temporary, and will be destroyed once the complete expression (TC(...)) is done.
In
template<typename TA>
const TA &ref_A_factory() {
return TA("a ref");
}
returning a reference to a local variable is undefined behavior.
In
TC(value_A_factory<A>(), ...)
the lifetime of the value returned by value_A_factory will be the end of the expression TC(...). After that your references in C are dangling.
If you really want to use interfaces and factories for polymorphic types, there is no real alternative to dynamic memory allocation and some kind of ownership scheme. The simplest would be for C to simply assume ownership of its members and take care of their deletion.
#include <memory>
#include <cassert>
struct IA {
virtual void doA() const = 0;
virtual ~IA() { };
};
struct A : IA {
void doA() const override {}
};
struct C {
/* C assumes ownership of a. a cannot be null. */
C(IA* a) : a{a} { assert(a && "C(IA* a): a was null"); };
private:
std::unique_ptr<IA> a;
};
C factory() {
return C{new A};
}
int main()
{
C c = factory();
return 0;
}
class MyClass {
public: MyClass(int a) : a(a) { }
int a;
};
#include <iostream>
void print(MyClass* a) { std::cout << a->a << std::endl; }
int main() {
print(&static_cast<MyClass&&>(MyClass(1337)));
return 0;
}
This doesn't work with GCC 4.6, while it used to work in a previous version.
Now it says: taking address of xvalue (rvalue reference).
Is there any way to securely pass the address of an rvalue to another function?
is: there is anyway to securely pass an rvalue reference (a.k.a. address of temporary) to another function without boringly storing it in a variable just to do that?
Yes, there is, like in the next example :
#include <iostream>
class MyClass {
public: MyClass(int a) : a(a) { }
int a;
};
void print(MyClass&& a) { std::cout << a.a << std::endl; }
int main() {
print( MyClass(1337) );
}
An rvalue does not necessarily have an address. However, there is a way to get the effect you want, by exploiting the fact that binding an rvalue to a reference forces it to be a temporary (which does have an address):
template<typename T> T *addressOfTemporary(T &&v) { return &v; }
Inside this function, v is an lvalue (despite being declared as T&&), so can have its address taken. You can use this function as follows:
class MyClass {
public: MyClass(int a) : a(a) { }
int a;
};
#include <iostream>
void print(MyClass* a) { std::cout << a->a << std::endl; }
int main() {
print(addressOfTemporary(MyClass(1337)));
return 0;
}
Note that the temporary's lifetime ends at the end of the full-expression (the print(...) expression, in this case), so you will need to be careful that the pointer is not used past that point.
If you don't particualrly need to print rvalues only, you can use a standard const reference instead:
class MyClass {
public: MyClass(int a) : a(a) { }
int a;
};
#include <iostream>
void print(const MyClass& a)
{ std::cout << a.a << std::endl; }
int main() {
print(MyClass(1337));
return 0;
}
I get a runtime error with the following code, which is a reproducible reduction of my actual code. I am sure I am not instantiating something properly, but I cannot figure out what it is.
#include <iostream>
using namespace std;
class A {
int n;
public:
A();
A(const int k);
int getn() const { return n; };
};
A::A() : n(0) {};
A::A(const int k) : n(k) {}
class B {
const A& myA;
public:
B(const A& anA);
int getn() const { return myA.getn(); };
};
B::B(const A& anA) : myA(anA) {}
class C {
const A& myA;
const B& myB;
public:
C(const A& anA);
int getn() const { return myB.getn(); };
};
C::C(const A& anA) : myA(anA), myB(myA) {}
class D {
A myA;
C myC;
public:
D(const int k);
int getAn() const { return myA.getn(); };
int getCn() const { return myC.getn(); };
};
D::D(const int k) : myA(k), myC(myA) {}
int main() {
D myD(10);
cerr << "A: " << myD.getAn() << '\n';
cerr << "C: " << myD.getCn() << '\n';
}
I either get a segmentation fault on the second line of output or "C:0", instead of "C:10" which I expect.
The problem is in this line:
C::C(const A& anA) : myA(anA), myB(myA) {}
myB is a reference. But to what? The answer is to a temporary. myB(myA) will construct a temp object that is assigned to your reference. Unfortunately this object will be destroyed after the Ctor exits.
Change your code to the following:
class C {
const A& myA;
const B myB;
public:...
and it should work.
BTW: I nearly always declare constructors with one argument as explicit. Do so and the compiler will warn you.
You are trying to initialize D::myC with reference to D::myA, this is not correct because object is not completely constructed at this moment.
D::D(const int k) : myA(k), myC(myA) {}
Only first pair of values output on running this program seem correct, the others don't. What is going on?
#include <iostream>
#include <vector>
class a
{
public:
class b
{
public:
a* parent;
void test()
{
std::cout<<parent->value<<std::endl;
}
} b1;
unsigned long value;
a()
{
b1.parent = this;
value = 2;
}
void go()
{
value++;
b1.test();
}
};
int main()
{
{
a a1;
a1.go();
std::cout<<a1.value<<std::endl;
}
std::cout<<std::endl;
{
a a1; a1 = a();
a1.go();
std::cout<<a1.value<<std::endl;
}
std::cout<<std::endl;
{
std::vector<a> a1; a1.push_back(a());
a1.at(0).go();
std::cout<<a1.at(0).value<<std::endl;
}
return 0;
}
You are missing a copy ctor and assignment operator for type 'a'. When copying or assigning objects, you consequently don't properly update their b1.parent. Instead, the b1.parent values point to a different 'a' object than their real parent.
To see this problem in action, use this in your existing code:
void go() {
value++;
std::cout << (this == b1.parent ? "as expected\n" : "uh-oh\n");
b1.test();
}
To fix it, modify class a:
a() : b1 (this), value (2) {} // a change from your default ctor
a(a const &x) : b1 (this), value (x.value) {}
a& operator=(a const &x) {
value = x.value;
return *this;
}
And modify class b (necessarily to use the ctor initializer as I do above):
b(a *parent) : parent (parent) {}