I have a pure virtual class, BaseClass, with no data members and a protected constructor. It exists only to provide the interface for a subclass (which is templated). I want just about all the functionality implemented in the base class. Functions that operate on these typically would return BaseClass&, to allow convenient chaining of operations.
All well and good until I try to throw an instance, returned by reference from one of the functions. In short, I am throwing a reference to an abstract class, but I'm secure in the knowledge that it's guaranteed to be a fully constructed child class instance with all virtual functions intact. That's why the BaseClass constructor is protected. I'm compiling against a C++14 compiler. It's refusing to allow me to throw an abstract class.
One of the main points of the class is that I can construct a subclass, immediately call functions on it to add information, and then throw it, all in one fell swoop:
throw String<72>().addInt(__LINE__).addText("mom says no"); //does not compile
but addText(), very reasonably, returns BaseClass&, and the compiler refuses.
How do I? Moving all the member functions into the subclass seems obscene. I can hack around it by static casting the whole expression before the throw:
throw static_cast<String<72&>( //works, ugly
BaseClassString<72>().addText(where).addText(why).addText(resolution));
and even create a macro to hide the ugly mechanics and ensure some safety, but am I missing something? This seems like case of C++ preventing a perfectly workable technique.
Why can't I throw an abstract class?
Due to [except.throw]
/3 Throwing an exception copy-initializes ([dcl.init], [class.copy.ctor]) a temporary object, called the exception object.
/5 When the thrown object is a class object, the constructor selected for the copy-initialization as well as the constructor selected for a copy-initialization considering the thrown object as an lvalue shall be non-deleted and accessible, even if the copy/move operation is elided ([class.copy.elision]).
You could have the derived class throw itself through a virtual void Throw() const member function. That would eliminate the casting at the callsite. The principle being similar to having a virtual clone function for polymorphic copying.
#include <iostream>
#include <sstream>
#include <string>
#include <variant>
#include <vector>
using std::cout;
using std::get;
using std::holds_alternative;
using std::ostream;
using std::ostringstream;
using std::string;
using std::variant;
using std::vector;
class Abc {
using info_t = variant<int, string>;
vector<info_t> v;
virtual auto subtext() const -> string = 0;
public:
virtual ~Abc();
Abc() = default;
Abc(Abc const&) = default;
auto addInt(int) -> Abc&;
auto addText(string) -> Abc&;
virtual void Throw[[noreturn]]() const = 0;
virtual void print(ostream&) const;
};
Abc::~Abc() = default;
auto Abc::addInt(int value) -> Abc& {
v.push_back(value);
return *this;
}
auto Abc::addText(string value) -> Abc& {
v.push_back(value);
return *this;
}
void Abc::print(ostream& out) const {
if (auto st = subtext(); !st.empty())
out << st << "\n";
for (auto&& x : v) {
if (holds_alternative<int>(x)) {
out << get<int>(x) << "\n";
} else if (holds_alternative<string>(x)) {
out << get<string>(x) << "\n";
} else {
out << "(unknown type)\n";
}
}
}
template <typename T>
class Concrete : public Abc {
T data;
auto subtext() const -> string override {
ostringstream ss;
ss << data;
return ss.str();
}
public:
Concrete(T value) : data{value} {}
void Throw[[noreturn]]() const override { throw *this; }
};
struct allow_ctad_t;
Concrete(allow_ctad_t)->Concrete<void>;
int main() {
try {
Concrete(1000).addInt(__LINE__).addText(__FILE__).addText("Just testing!").Throw();
} catch (Abc const& ex) {
ex.print(cout);
}
}
Related
I've narrowed down my problem to exactly this
#include <iostream>
#include <functional>
struct Foo {
std::function<Foo*()> lambda;
Foo()
:lambda([this](){return this;})
{}
};
int main(){
Foo a;
Foo b = a;
std::cout << &a << " " << a.lambda() << std::endl;
std::cout << &b << " " << b.lambda() << std::endl;
}
where the output is
0x7ffd9128b8a0 0x7ffd9128b8a0
0x7ffd9128b880 0x7ffd9128b8a0
I originally expected that this would always point to the instance that owned the lambda. However I forgot about copy construction. In this case the lambda captures this and then it is fixed and no matter how many times the lambda is copied it points to the original value of this.
Is there a way fix this so that lambda always has a reference to it's owning object this even under copy construction of the owning object.
Sounds like you need to provide your own special member functions, no? E.g., for the copy constructor:
Foo(const Foo& other)
:lambda([this](){return this;})
{}
Whilst #lubgr answered the question for what I asked I think it is worth noting the other solution I have for my exact problem. The question stemmed from building a class to encapsulate lazy initialisation of members. My original attempt was
template <typename T>
class Lazy {
mutable boost::once_flag _once;
mutable boost::optional<T> _data;
std::function<T()> _factory;
void Init() const { boost::call_once([&] { _data = _factory(); }, _once); }
public:
explicit Lazy(std::function<T()> factory):_once(BOOST_ONCE_INIT),_factory(factory){}
T& Value() {
Init();
return *_data;
}
};
which can be used like
class Foo {
int _a;
Lazy<int> _val;
Foo(a):_a(a):_val([this](){return this->_a+1;}){}
}
Foo f(10);
int val = f._val.Value();
but has the same problem that I asked in my question in that this is a circular reference that doesn't get preserved for copy construction. The solution is not to create a custom copy constructor and possibly move constructor but to fix the Lazy implementation class so that we can pass in an arg to the factory.
The new implementation of Lazy for members is
template <typename T, typename TThis>
class LazyMember {
mutable boost::once_flag _once;
mutable boost::optional<T> _data;
typedef std::function<T(TThis const*)> FactoryFn;
FactoryFn _factory;
void Init(TThis const * arg0) const { boost::call_once([&] { _data = _factory(arg0); }, _once); }
public:
explicit LazyMember(FactoryFn factory):_once(BOOST_ONCE_INIT),_factory(factory){}
T& Value(TThis const * arg0) { Init(arg0); return *_data; }
T const & Value(TThis const * arg0) const { Init(arg0); return *_data; }
};
which is used as
class Foo {
int _a;
Lazy<int> _val;
Foo(a):_a(a):_val([](Foo const * _this){return _this->_a+1;}){}
}
Foo f(10);
int val = f._val.Value(&f);
and this doesn't have the circular reference problems and thus doesn't require a custom copy/move constructor.
If you have a class Base with virtual methods and a class Implementation which implements the virtual methods, is there any way to cast std::shared_ptr < Implementation > & to std::shared < Base > &? The compiler allows this for const references, but for non const references it fails as in "Case A" in the code below. Is there an easy way to do this?
If not, how safe is my workaround "questionable_cast" in Case B?
#include <iostream>
#include <memory>
class Base
{
public:
virtual void set_value(int x) = 0;
};
class Implementation : public Base
{
public:
Implementation() : m_value(0) { }
void set_value(int x) override
{
m_value = x;
}
int get_value() const
{
return m_value;
}
private:
int m_value;
};
void do_something(std::shared_ptr<Base>& base)
{
base->set_value(5);
/// Code like this makes the non-const argument necessary
base = std::make_shared<Implementation>();
}
template <class T, class U>
std::shared_ptr<T>& questionable_cast(std::shared_ptr<U>& u)
{
/// This code is here to assure the cast is allowed
std::shared_ptr<T> tmp = u;
(void)tmp;
return *reinterpret_cast<std::shared_ptr<T>*>(&u);
}
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
// The following line causes a compiler error:
// invalid initialization of reference of type ‘std::shared_ptr<Base>&’ ...
// do_something(a);
// do_something(std::dynamic_pointer_cast<Base>(a));
// This is the workaround
do_something(questionable_cast<Base>(a));
std::cerr << "a = " << a->get_value() << std::endl;
return 0;
}
Two obvious solutions to the problem as originally asked: 1. Make do_something take a const reference to a shared_ptr (or a shared_ptr by value). 2. Create a named shared_ptr and pass a reference to that: Eg
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
std::shared_ptr<Base> b = a; // This conversion works.
do_something(b); // Pass a reference to b instead.
return 0;
}
Your questionable_cast function is a violation of the strict aliasing rules, and invokes undefined behaviour. It's quite likely to work in initial tests, and then a new release of the compiler will crank up the optimization a notch, and it will fail during a demo.
To handle the case where do_something changes the pointer:
int main()
{
std::shared_ptr<Implementation> a = std::make_shared<Implementation>();
std::shared_ptr<Base> b = a; // This conversion works.
do_something(b); // Pass a reference to b instead.
const auto aa = std::dynamic_pointer_cast<Implementation>(b);
if (aa)
a = aa;
else
; // Handle the error here
return 0;
}
If do_something guarantees to return a pointer of the same derived type, even if it doesn't return the same pointer, wrap it in a template function:
template <typename T>
void do_something_ex( std::shared_ptr<T>& a )
{
std::shared_ptr<Base> b = a;
do_something(b)
a = std::dynamic_pointer_cast<T>(b);
if (!a)
throw_or_assert;
}
Well, my colleague is pretty in depth nitpicking about eliminating unnecessarily code instantiations for destructor functions. Still same situation, as mentioned in this question:
Very limited space for .text section (less 256 KB)
Code base should scale among several targets, including the most limited ones
Well known use cases of the code base by means some destructor logic is neccesary to manage object lifetimes or not (for many cases life-time of objects is infinite, unless the hardware is reset)
We have a target, that's very limited by means of .text section space available.
Unfortunately the GCC compiler will apparently instantiate code for even non virtual destructors, that actually have no side effects.
To get rid of these instantiatons he came up with the following wrapper construct, to eliminate the useless destructor calls:
The wrapper class:
#include <iostream>
#include <cstdint>
#include <utility>
template <typename T>
struct noop_destructor {
public:
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
template<typename... Args>
noop_destructor(Args&&... args) {
new (reinterpret_cast<void*>(wrapped_data)) T(std::forward<Args>(args)...);
}
explicit noop_destructor(const noop_destructor& rhs) {
std::copy(rhs.wrapped_data,rhs.wrapped_data+sizeof(T),wrapped_data);
}
noop_destructor& operator=(const noop_destructor& rhs) {
std::copy(rhs.wrapped_data,rhs.wrapped_data+sizeof(T),wrapped_data);
return *this;
}
pointer operator->() {
return reinterpret_cast<pointer>(wrapped_data);
}
const_pointer operator->() const {
return reinterpret_cast<const_pointer>(wrapped_data);
}
reference operator*() {
return *reinterpret_cast<pointer>(wrapped_data);
}
const_reference operator*() const {
return *reinterpret_cast<const_pointer>(wrapped_data);
}
private:
uint8_t wrapped_data[sizeof(T)] __attribute__ ((aligned (__BIGGEST_ALIGNMENT__)));
};
A wrapped class (just ignore the side effect of calling std::cout << ... in the destructor, the real life classes in question to be wrapped, have just empty, non virtual destructors)
class A {
public:
A() : x_() {}
A(int x) : x_(x) {}
~A() {
std::cout << "noop destructor call of class A" << std::endl;
}
void foo() {
std::cout << "x_ = " << x_ << std::endl;
}
private:
int x_;
};
Some instantiations to demonstrate behavior:
int main() {
A a1(5);
noop_destructor<A> a2;
a1.foo();
(*a2).foo();
return 0;
}
The approach just works fine (as you can see from the above code sample).
What I actually don't like about it, is you have no proof if a class actually can be wrapped with noop_destructor<>, and there's no indicator if T's destructor is actually empty, and can be safely eliminated or not.
Does anyone have an idea, how to make this more safe from a semantical level?
I would like a class Value, which both has a run-time polymorphic behaviour, and a value semantics. For instance, I would like to be able to do things like:
// create polymorphic data
Value v1 = IntValue(42);
Value v2 = DoubleValue(12.3);
// copy-by-value semantics
Value v3 = v1;
v3.increments();
Value v4;
v4 = v2;
v4.increments();
// possibly put them in my favourite container
MyList<Value> l;
l << v1 << v2 << v3 << v4;
// print them: "Int(42) Double(12.0) Int(43) Double(13.0) "
for(int i=0; i<l.size(); i++) l[i].print();
Is it possible, and if yes, how?
Note: Using boost or C++11 smart pointers as here is not desired: they make the caller code verbose, use -> instead of ., and do not have copy constructors or assignment operators implementing a true value semantics. Also, this question doesn't target specifically containers.
polymorphic_value has been proposed for standardisation and has some of the semantics you require. You'll have to define your own operator << though.
A polymorphic_value<T> may hold a an object of a class publicly derived from T, and copying the polymorphic_value will copy the object of the derived type.
polymorphic_value<T> is implemented with type erasure and uses the compiler-generated copy-constructor of the derived objects to correctly copy objects stored as polymorphic_value<BaseType>.
Copy constructors and assignment operators are defined so that the objects are value-like. There is no need to use or define a custom clone method.
In brief:
template <class T>
struct control_block
{
virtual ~control_block() = default;
virtual T* ptr() = 0;
virtual std::unique_ptr<control_block> clone() const = 0;
};
template <class T>
class polymorphic_value {
std::unique_ptr<control_block<T>> cb_;
T* ptr_ = nullptr;
public:
polymorphic_value() = default;
polymorphic_value(const polymorphic_value& p) :
cb_(p.cb_->clone())
{
ptr_ = cb_->ptr();
}
T* operator->() { return ptr_; }
const T* operator->() const { return ptr_; }
T& operator*() { return *ptr_; }
const T& operator*() const { return *ptr_; }
// Some methods omitted/deferred.
};
Specializations of the control block allow other constructors to be defined.
Motivation and design is discussed here :
https://github.com/jbcoe/polymorphic_value/blob/master/talks/2017_1_25_cxx_london.md
and here
https://github.com/jbcoe/polymorphic_value/blob/master/draft.md
A full implementation with tests can be found here:
https://github.com/jbcoe/polymorphic_value
It's hard to know what you're trying to achieve here, but at first guess it seems that the (upcoming) Boost Type Erasure library might be suitable?
any<
mpl::vector<
copy_constructible<>,
typeid_<>,
incrementable<>,
ostreamable<>
>
> x(10);
++x;
std::cout << x << std::endl; // prints 11
(Example from docs).
Yes, it is possible, but of course there must be some hidden pointer, and the actual data must be stored on the heap. The reason is that the actual size of the data cannot be known at compile-time, and then can't be on the stack.
The idea is to store the actual implementation through a pointer of a polymorphic class ValueImpl, that provides any virtual method you need, like increments() or print(), and in addition a method clone(), so that your class Data is able to implement the value semantics:
class ValueImpl
{
public:
virtual ~ValueImpl() {};
virtual std::unique_ptr<ValueImpl> clone() const { return new ValueImpl(); }
virtual void increments() {}
virtual void print() const { std::cout << "VoidValue "; }
};
class Value
{
private:
ValueImpl * p_; // The underlying pointer
public:
// Default constructor, allocating a "void" value
Value() : p_(new ValueImpl) {}
// Construct a Value given an actual implementation:
// This allocates memory on the heap, hidden in clone()
// This memory is automatically deallocated by unique_ptr
Value(const ValueImpl & derived) : p_(derived.clone()) {}
// Destruct the data (unique_ptr automatically deallocates the memory)
~Value() {}
// Copy constructor and assignment operator:
// Implements a value semantics by allocating new memory
Value(const Value & other) : p_(other.p_->clone()) {}
Value & operator=(const Value & other)
{
if(&other != this)
{
p_ = std::move(other.p_->clone());
}
return *this;
}
// Custom "polymorphic" methods
void increments() { p_->increments(); }
void print() { p_->print(); }
};
The contained pointer is stored inside a C++11 std::unique_ptr<ValueImpl> to ensure the memory is released when destroyed or assigned a new value.
The derived implementations can finally be defined the following way:
class IntValue : public ValueImpl
{
public:
IntValue(int k) : k_(k) {}
std::unique_ptr<IntValue> clone() const
{
return std::unique_ptr<IntValue>(new IntValue(k_));
}
void increments() { k_++; }
void print() const { std::cout << "Int(" << k_ << ") "; }
private:
int k_;
};
class DoubleValue : public ValueImpl
{
public:
DoubleValue(double x) : x_(x) {}
std::unique_ptr<DoubleValue> clone() const
{
return std::unique_ptr<DoubleValue>(new DoubleValue(k_));
}
void increments() { x_ += 1.0; }
void print() const { std::cout << "Double(" << x_ << ") "; }
private:
int x_;
};
Which is enough to make the code snippet in the question works without any modification. This provides run-time polymorphism with value semantics, instead of the traditional run-time polymorphism with pointer semantics provided built-in by the C++ language. In fact, the concept of polymorphism (handling generic objects that behave differently according to their true "type") is independent from the concept of pointers (being able to share memory and optimize function calls by using the address of an object), and IMHO it is more for implementation details that polymorphism is only provided via pointers in C++. The code above is a work-around to take advantage of polymorphism when using pointers is not "philosophically required", and hence ease memory management.
Note: Thanks for CaptainObvlious for the contribution and his evolved code available here that I partially integrated. Not integrated are:
To ease the creation of derived implementations, you may want to create an intermediate templated class
You may prefer to use an abstract interface instead of my non-abstract base class
Recently I have read that it makes sense when returning by value from a function to qualify the return type const for non-builtin types, e.g.:
const Result operation() {
//..do something..
return Result(..);
}
I am struggling to understand the benefits of this, once the object has been returned surely it's the callers choice to decide if the returned object should be const?
Basically, there's a slight language problem here.
std::string func() {
return "hai";
}
func().push_back('c'); // Perfectly valid, yet non-sensical
Returning const rvalues is an attempt to prevent such behaviour. However, in reality, it does way more harm than good, because now that rvalue references are here, you're just going to prevent move semantics, which sucks, and the above behaviour will probably be prevented by the judicious use of rvalue and lvalue *this overloading. Plus, you'd have to be a bit of a moron to do this anyway.
It is occasionally useful. See this example:
class I
{
public:
I(int i) : value(i) {}
void set(int i) { value = i; }
I operator+(const I& rhs) { return I(value + rhs.value); }
I& operator=(const I& rhs) { value = rhs.value; return *this; }
private:
int value;
};
int main()
{
I a(2), b(3);
(a + b) = 2; // ???
return 0;
}
Note that the value returned by operator+ would normally be considered a temporary. But it's clearly being modified. That's not exactly desired.
If you declare the return type of operator+ as const I, this will fail to compile.
There is no benefit when returning by value. It doesn't make sense.
The only difference is that it prevents people from using it as an lvalue:
class Foo
{
void bar();
};
const Foo foo();
int main()
{
foo().bar(); // Invalid
}
Last year I've discovered another surprising usecase while working on a two-way C++-to-JavaScript bindings.
It requires a combination of following conditions:
You have a copyable and movable class Base.
You have a non-copyable non-movable class Derived deriving from Base.
You really, really do not want an instance of Base inside Derived to be movable as well.
You, however, really want slicing to work for whatever reason.
All classes are actually templates and you want to use template type deduction, so you cannot really use Derived::operator const Base&() or similar tricks instead of public inheritance.
#include <cassert>
#include <iostream>
#include <string>
#include <utility>
// Simple class which can be copied and moved.
template<typename T>
struct Base {
std::string data;
};
template<typename T>
struct Derived : Base<T> {
// Complex class which derives from Base<T> so that type deduction works
// in function calls below. This class also wants to be non-copyable
// and non-movable, so we disable copy and move.
Derived() : Base<T>{"Hello World"} {}
~Derived() {
// As no move is permitted, `data` should be left untouched, right?
assert(this->data == "Hello World");
}
Derived(const Derived&) = delete;
Derived(Derived&&) = delete;
Derived& operator=(const Derived&) = delete;
Derived& operator=(Derived&&) = delete;
};
// assertion fails when the `const` below is commented, wow!
/*const*/ auto create_derived() { return Derived<int>{}; }
// Next two functions hold reference to Base<T>/Derived<T>, so there
// are definitely no copies or moves when they get `create_derived()`
// as a parameter. Temporary materializations only.
template<typename T>
void good_use_1(const Base<T> &) { std::cout << "good_use_1 runs" << std::endl; }
template<typename T>
void good_use_2(const Derived<T> &) { std::cout << "good_use_2 runs" << std::endl; }
// This function actually takes ownership of its argument. If the argument
// was a temporary Derived<T>(), move-slicing happens: Base<T>(Base<T>&&) is invoked,
// modifying Derived<T>::data.
template<typename T>
void oops_use(Base<T>) { std::cout << "bad_use runs" << std::endl; }
int main() {
good_use_1(create_derived());
good_use_2(create_derived());
oops_use(create_derived());
}
The fact that I did not specify the type argument for oops_use<> means that the compiler should be able to deduce it from argument's type, hence the requirement that Base<T> is actually a real base of Derived<T>.
An implicit conversion should happen when calling oops_use(Base<T>). For that, create_derived()'s result is materialized into a temporary Derived<T> value, which is then moved into oops_use's argument by Base<T>(Base<T>&&) move constructor. Hence, the materialized temporary is now moved-from, and the assertion fails.
We cannot delete that move constructor, because it will make Base<T> non-movable. And we cannot really prevent Base<T>&& from binding to Derived<T>&& (unless we explicitly delete Base<T>(Derived<T>&&), which should be done for all derived classes).
So, the only resolution without Base modification here is to make create_derived() return const Derived<T>, so that oops_use's argument's constructor cannot move from the materialized temporary.
I like this example because not only it compiles both with and without const without any undefined behaviour, it behaves differently with and without const, and the correct behavior actually happens with const only.