Debugging crash in small object optimization for type erasure - c++

I'm implementing a class that performs type erasure for small objects and have encountered a segmentation fault which I do not understand.
The following program:
#include <iostream>
#include <type_traits>
struct small_object
{
public:
template<class T>
small_object(const T& value)
{
new(&storage_) concrete<T>(value);
}
~small_object()
{
get_abstract().~abstract();
}
void print() const
{
// XXX crash here
get_abstract().print();
}
private:
struct abstract
{
virtual ~abstract(){}
virtual void print() const = 0;
};
template<class T>
struct concrete
{
concrete(const T& value) : value_(value) {}
void print() const
{
std::cout << value_ << std::endl;
}
T value_;
};
abstract& get_abstract()
{
return *reinterpret_cast<abstract*>(&storage_);
}
const abstract& get_abstract() const
{
return *reinterpret_cast<const abstract*>(&storage_);
}
typename std::aligned_storage<4 * sizeof(void*)> storage_;
};
int main()
{
small_object object(13);
// XXX i expect this line to print '13' to the terminal but it crashes
object.print();
return 0;
}
Crashes at the lines indicated by XXX.
I believe the issue is that the virtual call to .print() is not being dynamically dispatched correctly, but I don't understand why.
Can anyone tell what am I missing?

You didn't derive concrete<T> from abstract, so no vtable is being created when you construct the object using placement new. Therefore, when you try to invoke the virtual function, it will fail; concrete<T> and abstract are actually completely unrelated types in this example.
I would recommend using the override keyword if you're using C++11 or newer to allow the compiler to generate an error in cases like this.

std::aligned_storage<4 * sizeof(void*)> storage_;
This creates storage of one byte.
The template argument does not set the size of the declared object, but rather the size of an object that can be allocated in a suitably-sized array of this type. Hence, you need
std::aligned_storage<4 * sizeof(void*)> storage_[4 * sizeof(void*)];
GCC 6.2.0 warns you about this:
warning: placement new constructing an object of type ‘small_object::concrete<int>’ and size ‘16’ in a region of type ‘std::aligned_storage<32ul>’ and size ‘1’ [-Wplacement-new=]
(You still need to derive concrete from abstract).

Related

Map of template function

I have a class like this:
class factory;
using factory_ptr = std::unique_ptr<IComponent> (factory::*)() const noexcept;
class factory {
public:
factory();
~factory() = default;
std::unique_ptr<Chipset> &create(const std::string &type);
private:
template<class T>
std::unique_ptr<T> Tcreate() const noexcept;
std::map<std::string, factory_ptr> m_fac;
};
#include "factory.inl"
My template function Tcreate is just:
template<class T>
std::unique_ptr<T> factory::Tcreate() const noexcept {
return std::make_unique<T>();
}
And the other function are just:
factory::factory() {
m_fac.emplace("4001", &factory::Tcreate<chipset4001>);
m_fac.emplace("4008", &factory::Tcreate<chipset4008>);
m_fac.emplace("4011", &factory::Tcreate<chipset4011>);
m_fac.emplace("4030", &factory::Tcreate<chipset4030>);
m_fac.emplace("4069", &factory::Tcreate<chipset4069>);
m_fac.emplace("4071", &factory::Tcreate<chipset4071>);
m_fac.emplace("4081", &factory::Tcreate<chipset4081>);
m_fac.emplace("4512", &factory::Tcreate<chipset4512>);
}
std::unique_ptr<Chipset> &factory::create(const std::string &type) {
if (m_fac.find(type) == m_fac.end()) {
throw nts::exception("can't find the chipset: " + type, "FactoryCreate");
}
return (this->*(m_fac.find(type)->second))();
}
Every chipset like chipsetXXXX are a class like:
class chipsetXXXX : Chipset {}
What I want to do here with this code is to generate an std::unique_ptr<> of a certain chipset linked with a string (cf. factory::m_fac), but when I run it a lot of error message pop on my terminal (more than what my terminal can handle). but i can't figured out what go wrong with it.
The issue is that your Tcreate function does not have the required signature. You're trying to create a map of functions which return an std::unique_ptr<IComponent>, but Tcreate() returns std::unique_ptr<T>.
I'm assuming Chipset inherits from IComponent. And as you note each T inherits from Chipset. So the conversion from e.g. std::unique_ptr<chipset4001> to std::unique_ptr<IComponent> is certainly possible, but that doesn't mean that the signature matches. E.g. a pointer to a function double do_thing () can't be assigned to a function pointer expecting an int (*) ().
So the solution is to change the return type of Tcreate to std::unique_ptr<IComponent>:
template<class T>
std::unique_ptr<IComponent> factory::Tcreate() const noexcept {
return std::make_unique<T>();
}
However, when you do that, you'll now get a compile error in create(), because that tries to return an std::unique_ptr<Chipset>. It's up to you to decide what to do there. Either return std::unique_ptr<IComponent>, or change factory_ptr to be a pointer to a function returning std::unique_ptr<Chipset> (and of course change Tcreate() accordingly).

C++11 GCC 4 Fast Optimization don't store implementation class from abstract class in the stack

So guys, I have an abstract class, other class that stores an implementation from this class in the stack (I don't want heap allocations and I don't know other way to do it without making the caller explicitly declares the implementation) and another that stores a reference of this interface class. But, it seems that GCC don't store the implementation class in the stack and when the interface class is used probably the implementation class vtable is not found.
Basically, everything works fine when compiled with GCC 4.8.1 without optimizations, but when I try to use it, the program crashes and then returns 139.
I don't know why GCC 4 doesn't support it, while GCC 5 does, but I see that they generate different instructions.
Compiler Explorer: https://godbolt.org/z/Wfvj65
#include <cstdio>
#define FORCEINLINE inline __attribute__((always_inline))
class IFormatter
{
public:
virtual void Format(const void* InData) const = 0;
};
template<typename T>
class TFormatter :
public IFormatter
{
public:
TFormatter() = delete;
};
using Scalar = float;
// Implemented, fine.
struct RVector2
{
Scalar X;
Scalar Y;
};
// Not implemented, get error.
struct RVector3
{
Scalar X;
Scalar Y;
Scalar Z;
};
template<>
class TFormatter<RVector2> :
public IFormatter
{
public:
virtual void Format(const void*) const override
{
printf("[RVector2]\n");
}
};
template<typename T>
class TCustom
{
public:
FORCEINLINE TCustom(const T& InValue) :
Value(InValue),
Format(TFormatter<T>{})
{
}
FORCEINLINE const T* Data() const
{
return &Value;
}
FORCEINLINE const IFormatter& Formatter() const
{
return Format;
}
private:
const T& Value;
TFormatter<T> Format;
};
template<typename T>
FORCEINLINE TCustom<T> MakeCustom(const T& InValue)
{
return TCustom<T>{ InValue };
}
class RCustom
{
public:
FORCEINLINE RCustom(const void* InValue, const IFormatter& InFormatter) :
Data(InValue),
Formatter(InFormatter)
{
}
template<typename T>
FORCEINLINE RCustom(TCustom<T> const& InCustom) :
RCustom(InCustom.Data(), InCustom.Formatter())
{
}
FORCEINLINE const IFormatter& Get() const
{
return Formatter;
}
private:
const void* Data;
const IFormatter& Formatter;
};
int main()
{
const RVector2 Vector{};
const RCustom Custom = MakeCustom(Vector);
Custom.Get().Format(nullptr);
return 0;
}
As one of the comments said there is something weird going on with storing TCustom in the unrelated type RCustom. The implicit constructor RCustom(TCustom) threw me off.
The issue is quite subtle. If something works with -O0 but not with -Ofast (or -O2/-O3), most of the time something funny is happening with the memory. As Benny K said, in your case the issue is that RCustom only stores a reference to IFormatter:
class RCustom {
...
const IFormatter& Formatter; // Asking for problems
}
This is seems like an innocent &, but in fact this is dangerous. Because the validity of this member is dependent on the lifetime of an external object. There are a few possibilities to fix this. You could save a copy of the TFormatter in RCustom (instead of a reference):
template<typename T>
class RCustom {
...
const TFormatter<T> Formatter;
}
But this also means you have to give up the abstract interface IFormatter for the concrete one TFormatter<T>. To work with virtual methods in C++ you need a pointer, but using a raw-pointer will introduce the same memory problems as the references. So I suggest you use smart pointers:
class RCustom {
...
std::shared_ptr<const IFormatter> Formatter;
}
PS: to be precise about what's going wrong: In MakeCustom() you initialize a TCustom object which initializes and copies an instance of TFormatter. Next a reference to the instance of TFormatter in TCustom is saved in RCustom. Now this RCustom object is returned and the function MakeCustom() is cleaned up. In this cleaning process TCustom is destroyed, and so is the TFormatter-member. But the RCustom still retains a reference to this invalid memory. In C++ the difference between an & and no & is rather important.

Is there a way to simultaneously assign a type to multiple templates in C++?

This question is based on the example code below, which is inspired by Sean Parent's talk.
The goal of the code below is to provide an object wrapper similar to boost::any. I wrote this code to educate myself of type erasure. So, there is no practical uses this code intends (considering there is already boost::any).
class ObjWrap {
public:
template <typename T>
ObjWrap(T O) : Self(new Obj<T>(std::move(O))) {}
template <typename T>
friend typename T * getObjPtr(ObjWrap O) {
return static_cast<T*>(O.Self->getObjPtr_());
}
private:
struct Concept {
virtual ~Concept() = 0;
virtual void* getObjPtr_() = 0;
};
template <typename T>
struct Obj : Concept {
Obj(T O) : Data(std::move(O)) {}
void* getObjPtr_() { return static_cast<void*>(&Data); }
T Data;
};
std::unique_ptr<Concept> Self;
};
Before I can really ask my question, let's examine the code in the following aspects:
Concept::getObjPtr_ returns void* because a) Concept cannot be a template otherwise unique_ptr<Concept> Self would not work; b) void* is the only way I know how to return Obj::Data in a type-agnostic way in C++. Please correct me if this is wrong...
T * getObjPtr(ObjWrap O) is a template that needs instantiation separately from the ObjWrap constructor.
The use of ObjWrap basically includes: a) make a new ObjWrap over an existing object; b) retrieve the underlying object given an ObjWrap. For example:
ObjWrap a(1);
ObjWrap b(std::string("b"));
int* p_a = getObjPtr<int>(a);
std::string* p_b = getObjPtr<std::string>(b);
This works but it is obvious that getObjPtr<int>(b) does not work as intended.
So, my question is:
Is there a way to fix the above code so that we can simply use int* p_a = getObjPtr(a) and std::string* p_b = getObjPtr(b) or better yet auto p_a = getObjPtr(a) and auto p_b = getObjPtr(b)? In other words, is there a way in C++ to instantiate two templates at the same time (if so, we can instantiate the ObjWrap constructor and T* getObjPtr(ObjWrap) at compile time of a ObjWrap object, e.g., ObjWrap a(1))?
Edit 1:
Making ObjWrap a templated class does not help since it defeats the purpose of type erasure.
template <typename T>
class ObjWrap {
/* ... */
};
ObjWrap<int> a(1); // this is no good for type erasure.
Edit 2:
I was reading the code and realize that it can be modified to reflect the idea a little better. So, please also look at the following code:
class ObjWrap {
public:
template <typename T>
ObjWrap(T O) : Self(new Obj<T>(std::move(O))) {}
template <typename T>
T * getObjPtr() {
return static_cast<T*>(Self->getObjPtr_());
}
private:
struct Concept {
virtual ~Concept() = 0;
virtual void* getObjPtr_() = 0;
};
template <typename T>
struct Obj : Concept {
Obj(T O) : Data(std::move(O)) {}
void* getObjPtr_() { return static_cast<void*>(&Data); }
T Data;
};
std::unique_ptr<Concept> Self;
};
int main() {
ObjWrap a(1);
ObjWrap b(std::string("b"));
int* p_a = a.getObjPtr<int>();
std::string* p_b = b.getObjPtr<std::string>();
std::cout << *p_a << " " << *p_b << "\n";
return 0;
}
The main difference between this version of the code versus the one above is that T * getObjPtr() is a member function that is encapsulated by the ObjWrap object.
Edit 3:
My question regarding type erasure is answered by accepted answer. However, the question on simultaneous type instantiation to multiple templates is yet to be answered. My guess is currently C++ does not allow it but it would be nice to hear from people with more experience on that.
There are a few things that may help.
First thing to say is that if Obj ever needs to expose the address of the object, it's not Sean Parent's 'inheritance is the root of all evil' type-erasing container.
The trick is to ensure that the interface of Obj offers all semantic actions and queries the wrapper will ever need.
In order to provide this, it's often a reasonable idea to cache the address of the object and its type_id in the concept.
Consider the following updated example, in which there is one public method - operator==. The rule is that two Objs are equal if they contain the same type of object and those objects compare equal.
Note that the address and type_id:
1) are implementation details and not exposed on the interface of Obj
2) are accessible without virtual calls, which short-circuits the not-equal case.
#include <memory>
#include <utility>
#include <typeinfo>
#include <utility>
#include <cassert>
#include <iostream>
class ObjWrap
{
public:
template <typename T>
ObjWrap(T O) : Self(new Model<T>(std::move(O))) {}
// objects are equal if they contain the same type of model
// and the models compare equal
bool operator==(ObjWrap const& other) const
{
// note the short-circuit when the types are not the same
// this means is_equal can guarantee that the address can be cast
// without a further check
return Self->info == other.Self->info
&& Self->is_equal(other.Self->addr);
}
bool operator!=(ObjWrap const& other) const
{
return !(*this == other);
}
friend std::ostream& operator<<(std::ostream& os, ObjWrap const& o)
{
return o.Self->emit(os);
}
private:
struct Concept
{
// cache the address and type here in the concept.
void* addr;
std::type_info const& info;
Concept(void* address, std::type_info const& info)
: addr(address)
, info(info)
{}
virtual ~Concept() = default;
// this is the concept's interface
virtual bool is_equal(void const* other_address) const = 0;
virtual std::ostream& emit(std::ostream& os) const = 0;
};
template <typename T>
struct Model : Concept
{
Model(T O)
: Concept(std::addressof(Data), typeid(T))
, Data(std::move(O)) {}
// no need to check the pointer before casting it.
// Obj takes care of that
/// #pre other_address is a valid pointer to a T
bool is_equal(void const* other_address) const override
{
return Data == *(static_cast<T const*>(other_address));
}
std::ostream& emit(std::ostream& os) const override
{
return os << Data;
}
T Data;
};
std::unique_ptr<Concept> Self;
};
int main()
{
auto x = ObjWrap(std::string("foo"));
auto y = ObjWrap(std::string("foo"));
auto z = ObjWrap(int(2));
assert(x == y);
assert(y != z);
std::cout << x << " " << y << " " << z << std::endl;
}
http://coliru.stacked-crooked.com/a/dcece2a824a42948
(etc. etc.) Please correct me if this is wrong...
Your premise is wrong at least in principle, if not also in practice. You're insisting on making getObjPtr() a virtual method, and using an abstract base class. But - you've not established this is necessary. Remember - using virtual methods is expensive! Why should I pay for virtuals just to get type erasure?
Is there a way to fix the above code so that we can simply use int* p_a = getObjPtr(a)
Take Sean Parent's talk title to heart (as opposed to the fact that he does use inheritance in the talk), drop the inheritance and the answer should be Yes. Edit: It's sufficient for the code that erases the type and the code that un-erases the type to know what the type is - as long as you don't need to act on the type-erased data in a type-specific way. In Sean Parent's talk, you need to be able to make non-trivial copies of it, to move it, to draw it etc. With std::any/boost::any you might need copying and moving, which may require virtuals - but that's the most general use case.
Even std::any limits what you can and can't do, as is discussed in this question:
why doesn't std::any_cast support implicit conversion?

Pointer to member template classes

AbstractFieldCollection is the base class of hardwareMissingAlarm, etc.
hardwareMissingAlarm belongs to another class that is a template.
alarmFieldCollection.push_back((AbstractAlarmField Device::*) &Device::hardwareMissingAlarm);
alarmFieldCollection.push_back((AbstractAlarmField Device::*) &Device::hardwareErrorAlarm);
alarmFieldCollection.push_back((AbstractAlarmField Device::*) &Device::badConfigAlarm);``
Then in another function I'm reading the vector like this:
for(int32_t i=0; i<alarmFieldCollection.size(); i++)
{
AbstractAlarmField Device::* pAF = alarmFieldCollection[i];
std::cout << "isRaised: "<< pDev << std::endl;
if ((pDev->*pAF).isRaised(pContext))
{
.....
}
}
and pDev is the Device object, however pDev->*pAF returns NULL. In fact when I'm printing &Device::hardwareErrorAlarm, &Device::hardwareMissingAlarm the result is 1. I don't know what I'm doing wrong.
isRaised is a method that belongs to the class AbstractAlarmField.
Thanks in advance.
You provided almost no code but it seems like you are storing an abstract object by value, not by reference or pointer. This may lead to object slicing and any kind of memory problem as a consequence. Try to use AbstractAlarmField& as the type of Device fields instead.
It is not useful to convert a member pointer X C::* to Y C::*. The Standard allows it as a reinterpret_cast or C-style cast, but with entirely unspecified results (unless you convert back to the original type). You would be better off using a virtual functor to safely get the AbstractAlarmField subobject:
#include <type_traits>
#include <memory>
struct AlarmGetter {
public:
virtual ~AlarmGetter();
virtual AbstractAlarmField& get(Device& dev) const = 0;
};
template <typename T>
struct AlarmMemberPtr
: public AlarmGetter {
static_assert(std::is_base_of<AbstractAlarmField, T>::value,
"Member type is not an AbstractAlarmField");
public:
explicit AlarmMemberPtr(T Device::*member)
: m_member( member ) {}
virtual AbstractAlarmField& get(Device& dev) const {
return dev.*m_member;
}
private:
T Device::*m_member;
};
template <typename T>
std::unique_ptr<AlarmGetter> make_alarm_getter(T Device::*member) {
std::unique_ptr<AlarmGetter> ptr(new AlarmMemberPtr<T>(member));
return ptr;
}
// To populate:
std::vector<std::unique_ptr<AlarmGetter>> alarmFieldCollection;
alarmFieldCollection.push_back(make_alarm_getter(&Device::hardwareMissingAlarm));
alarmFieldCollection.push_back(make_alarm_getter(&Device::hardwareErrorAlarm));
alarmFieldCollection.push_back(make_alarm_getter(&Device::badConfigAlarm));
// To use:
if (alarmFieldCollection[i]->get(*pDev).isRaised(pContext))
If it might be useful, you could also easily add an overload
virtual const AbstractAlarmField& get(const Device& dev) const;

C++ Push Multiple Types onto Vector

Note: I know similar questions to this have been asked on SO before, but I did not find them helpful or very clear.
Second note: For the scope of this project/assignment, I'm trying to avoid third party libraries, such as Boost.
I am trying to see if there is a way I can have a single vector hold multiple types, in each of its indices. For example, say I have the following code sample:
vector<something magical to hold various types> vec;
int x = 3;
string hi = "Hello World";
MyStruct s = {3, "Hi", 4.01};
vec.push_back(x);
vec.push_back(hi);
vec.push_back(s);
I've heard vector<void*> could work, but then it gets tricky with memory allocation and then there is always the possibility that certain portions in nearby memory could be unintentionally overridden if a value inserted into a certain index is larger than expected.
In my actual application, I know what possible types may be inserted into a vector, but these types do not all derive from the same super class, and there is no guarantee that all of these types will be pushed onto the vector or in what order.
Is there a way that I can safely accomplish the objective I demonstrated in my code sample?
Thank you for your time.
The objects hold by the std::vector<T> need to be of a homogenous type. If you need to put objects of different type into one vector you need somehow erase their type and make them all look similar. You could use the moral equivalent of boost::any or boost::variant<...>. The idea of boost::any is to encapsulate a type hierarchy, storing a pointer to the base but pointing to a templatized derived. A very rough and incomplete outline looks something like this:
#include <algorithm>
#include <iostream>
class any
{
private:
struct base {
virtual ~base() {}
virtual base* clone() const = 0;
};
template <typename T>
struct data: base {
data(T const& value): value_(value) {}
base* clone() const { return new data<T>(*this); }
T value_;
};
base* ptr_;
public:
template <typename T> any(T const& value): ptr_(new data<T>(value)) {}
any(any const& other): ptr_(other.ptr_->clone()) {}
any& operator= (any const& other) {
any(other).swap(*this);
return *this;
}
~any() { delete this->ptr_; }
void swap(any& other) { std::swap(this->ptr_, other.ptr_); }
template <typename T>
T& get() {
return dynamic_cast<data<T>&>(*this->ptr_).value_;
}
};
int main()
{
any a0(17);
any a1(3.14);
try { a0.get<double>(); } catch (...) {}
a0 = a1;
std::cout << a0.get<double>() << "\n";
}
As suggested you can use various forms of unions, variants, etc. Depending on what you want to do with your stored objects, external polymorphism could do exactly what you want, if you can define all necessary operations in a base class interface.
Here's an example if all we want to do is print the objects to the console:
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class any_type
{
public:
virtual ~any_type() {}
virtual void print() = 0;
};
template <class T>
class concrete_type : public any_type
{
public:
concrete_type(const T& value) : value_(value)
{}
virtual void print()
{
std::cout << value_ << '\n';
}
private:
T value_;
};
int main()
{
std::vector<std::unique_ptr<any_type>> v(2);
v[0].reset(new concrete_type<int>(99));
v[1].reset(new concrete_type<std::string>("Bottles of Beer"));
for(size_t x = 0; x < 2; ++x)
{
v[x]->print();
}
return 0;
}
In order to do that, you'll definitely need a wrapper class to somehow conceal the type information of your objects from the vector.
It's probably also good to have this class throw an exception when you try to get Type-A back when you have previously stored a Type-B into it.
Here is part of the Holder class from one of my projects. You can probably start from here.
Note: due to the use of unrestricted unions, this only works in C++11. More information about this can be found here: What are Unrestricted Unions proposed in C++11?
class Holder {
public:
enum Type {
BOOL,
INT,
STRING,
// Other types you want to store into vector.
};
template<typename T>
Holder (Type type, T val);
~Holder () {
// You want to properly destroy
// union members below that have non-trivial constructors
}
operator bool () const {
if (type_ != BOOL) {
throw SomeException();
}
return impl_.bool_;
}
// Do the same for other operators
// Or maybe use templates?
private:
union Impl {
bool bool_;
int int_;
string string_;
Impl() { new(&string_) string; }
} impl_;
Type type_;
// Other stuff.
};