Crash due to mixing CRTP & interfaces? - c++

I am experimenting with CRTP and mixing it with interfaces, and I cannot explain why this program crashes (in Clang, GCC and MSVC). In latest Clang and GCC it builds without warning with -Wall, -Wextra. My guess is that the virtual method call is not resolved but I cannot explain why (no crash if GetInt() is removed from the interface). In my debugger I see that the crash happens on line static_cast<T*>(this)->GetInt().
#include <iostream>
class INode
{
public:
virtual int GetInt() = 0;
protected:
~INode() {}
};
template<template<class> typename NodeBase>
class Node : public INode, public NodeBase<Node<NodeBase>>
{
public:
int GetInt() override { return 42; }
};
template<typename T>
class MyNodeBase
{
public:
int CallGetInt() {
return static_cast<T*>(this)->GetInt();
}
};
template<template<class> typename NodeBase>
int Foo1(Node<NodeBase> n) {
return n.CallGetInt();
}
template<typename T>
int Foo2(MyNodeBase<T> n) {
return n.CallGetInt();
}
int main() {
Node<MyNodeBase> n;
std::cout << Foo1(n) << std::endl; // ok
std::cout << Foo2(n) << std::endl; // crash
}

You're slicing n in your call to Foo2.
Foo2 accepts its parameter by value. That means that a copy of n's MyNodeBase<Node<MyNodeBase>> sub-object is what gets passed to Foo2. Since n in Foo2 is not a Node<MyNodeBase>, calling GetInt through the pointer returned from the cast in CallGetInt results in your program exhibiting undefined behavior.
If you change Foo2 to accept its parameter by reference, you program's behavior would be well-defined.

Foo2 argument is passed by value. So the complete object n is of type MyNodeBase<Node<MyNodeBase>>. It is not a derived of Node<MyNodeBase>. But the expression static_cast<T*>(this) assumes that this is derived of Node<MyNodeBase> thus static_cast<T*>(this)->GetInt() is undefined behavior.
You avoid this error:
template<typename T>
class MyNodeBase
{
protected:
MyNodeBase() = default;
MyNodeBase(const MyNodeBase&) = default;
MyNodeBase& operator = (const MyNodeBase&) = default;
public:
int CallGetInt() {
return static_cast<T*>(this)->GetInt();
}
};

Related

clang static analyzer reports memory leak using unique_ptr. False positive?

I have a class that uses std::unique_ptr for memory, but clang-check reports a "potential leak of memory". I can't figure out why and if I'm doing something wrong or if this is a false positive. Running valgrind finds no leaks.
The code (see below) is nested several layers, I could not reduce it further while still triggering the leak check.
Essentially, I have a class Func that acts similar to std::function, i.e. it is a type-erased wrapper for any functor object that provides the (duck-typed) interface double operator()(double x) const. It wraps this object using a std::unique_ptr<Callable>, where Callable is the interface for said method (and has a virtual destructor and clone for polymorphic copy). Type erasure is implemeted using the class template CallableImpl that has the actual functor as a member.
Thus, objects of type Func have value semantics and should be copy-able in any way without leaking memory, due to unique_ptr and the virtual dtor.
I then have several auxiliary classes that just exercise this, wrapped into each other, to trigger the leak check.
#include <iostream>
#include <memory>
// Interface for a functor object providing method double operator()(double)
class Callable
{
public:
using FuncPtr = std::unique_ptr<Callable>;
Callable() = default;
virtual ~Callable() = default;
// Call function
virtual double operator()(double x) const = 0;
// Polymorphic copy constructor
virtual FuncPtr clone() const = 0;
};
// Generic implementation that equips Functor with the Callable interface
// as long as it provides the required (non-virtual) method.
template <typename Functor>
class CallableImpl : public Callable
{
public:
CallableImpl(Functor f) : f(std::move(f)) {}
CallableImpl(const CallableImpl&) = default;
CallableImpl(CallableImpl&&) = default;
double operator()(double x) const override
{
return f(x);
}
FuncPtr clone() const override
{
return std::make_unique<CallableImpl>(*this);
}
private:
Functor f;
};
// Type-erased functor
class Func final
{
using FuncPtr = Callable::FuncPtr;
FuncPtr func;
public:
// Type erasing constructor for generic callables
template <typename T>
Func(T callable)
: func(std::make_unique<CallableImpl<T>>(std::move(callable)))
{
}
// Copy constructor
Func(const Func& rhs) : func(rhs.func->clone()) {}
// Move constructor
Func(Func&&) = default;
// Copy assignment
Func& operator=(const Func& rhs)
{
func = rhs.func->clone();
return *this;
}
// Move assignment
Func& operator=(Func&& rhs) = default;
// Call function
double operator()(double x) const
{
return (*func)(x);
}
};
// A class that implements the Callable concept of Func, including some state
class AddConstant
{
public:
AddConstant(double c) : c(c) {}
double operator()(double x) const { return x + c; }
private:
double c;
};
// A class that takes a Func and trivially executes
class Foo
{
public:
Foo(Func f) : f(std::move(f)) {}
double operator()(double x) const { return f(x); }
private:
Func f;
};
// Some additional wrapping that should do nothing but is needed for the
// leak warning to trigger.
struct WrapFoo
{
Foo f;
};
// This is also needed tp trigger the warning for some reason, although directly
// using the expression herein works fine.
WrapFoo makeWrapFoo(const Func& fa)
{
return {Foo(fa)};
}
int main()
{
AddConstant callable = AddConstant(3); // ok
Func func = {AddConstant(3)}; // ok
Foo foo = {func}; // ok
Foo copy = foo; // ok
WrapFoo wrappedFoo = WrapFoo{Foo(func)}; // ok
WrapFoo wrapper = makeWrapFoo(func); // Potential leak of memory
std::cout << "f(42): " << wrapper.f(42)
<< ", direct: " << callable(42) << std::endl;
}
The clang analyzer (clang version 12.0.0) output is:
$ /opt/homebrew/Cellar/llvm/12.0.0/libexec/c++-analyzer -std=c++17 main.cpp
main.cpp:124:5: warning: Potential leak of memory pointed to by field '__value_' [cplusplus.NewDeleteLeaks]
WrapFoo wrapper = makeWrapFoo(func); // Potential leak of memory
^~~~~~~~~~~~~~~
1 warning generated.
This is on libc++. On a linux machine whith libstdc++ I also get the warning.

My lambda does not correctly convert the captured 'this' during copy construction

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.

Why does initializing pointer of class A through method in class B in a segmentation fault?

I have the following code: (live on Coliru)
#include <iostream>
class ClassA{
public:
ClassA(int i) : m_int(i){};
int m_int;
};
class Master{
public:
Master(){};
~Master(){
delete m_classMain;
}
ClassA* m_classMain;
template<typename T>
void mem(T* t, int i){
t = new T(i);
}
void test() {
mem(m_classMain,3);
}
int get_i() const{
return m_classMain->m_int;
}
};
int main()
{
Master* master = new Master();
master->test();
std::cout << master->get_i() << std::endl;
delete master;
}
I would like to initialize the object ClassA* m_classMain through the method mem(T* t, int i) which is a template method.
For some reason I only get a segmentation fault. I think t = new T(i) might be the problem here, but I can not figure why (unfortunately I do not have a debugger at hand).
In your posted code, the member variable m_classMain is not initialized. Calling delete on it is cause for undefined behavior.
The call
mem(m_classMain,3);
does not initialize m_classMain since you are passing it by value. To initialize it in mem, you'll have to pass it by reference.
template<typename T>
void mem(T*& t, int i){ //T*& t, not T* t.
t = new T(i);
}
As a matter of good coding practice, make sure that all member variables are initialized in the constructor(s).
Master() : m_classMain(nullptr) {};
You are passing the t parameter of the mem() function by value. It gets destroyed on function exit. Consider passing by reference, or accessing the member directly from the member function.

Implicitly cast wrapper class to supperclass in templated call

In designing a DSL (which compiles into C++), I found it convenient to define a wrapper class that, uppon destruction, would call a .free() method on the contained class:
template<class T>
class freeOnDestroy : public T {
using T::T;
public:
operator T&() const { return *this; }
~freeOnDestroy() { T::free(); }
};
The wrapper is designed to be completely transparent: All methods, overloads and constructors are inherited from T (at least to my knowledge), but when included in the wrapper, the free() method is called uppon destruction. Note that I explicitly avoid using T's destructor for this since T::free() and ~T() may have different semantics!
All this works fine, untill a wrapped class gets used as a member to a non-reference templated call, at which point freeOnDestroy is instantiated, calling free on the wrapped object. What I would like to happen is for the tempated method to use T instead of freeOnDestroy<T>, and to implicitly cast the parameter into the supperclass. The following code sample illustrates this problem:
// First class that has a free (and will be used in foo)
class C{
int * arr;
public:
C(int size){
arr = new int[size];
for (int i = 0; i < size; i++) arr[i] = i;
}
int operator[] (int idx) { return arr[idx]; }
void free(){ cout << "free called!\n"; delete []arr; }
};
// Second class that has a free (and is also used in foo)
class V{
int cval;
public:
V(int cval) : cval(cval) {}
int operator[] (int idx) { return cval; }
void free(){}
};
// Foo: in this case, accepts anything with operator[int]
// Foo cannot be assumed to be written as T &in!
// Foo in actuality may have many differently-templated parameters, not just one
template<typename T>
void foo(T in){
for(int i = 0; i < 5; i++) cout << in[i] << ' ';
cout << '\n';
}
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(c); // OK!
foo(v); // OK!
foo<C>(f_c); // OK, but the base (C) of f_c may not be explicitly known at the call site, for example, if f_c is itself received as a template
foo(f_c); // BAD: Creates a new freeOnDestroy<C> by implicit copy constructor, and uppon completion calls C::free, deleting arr! Would prefer it call foo<C>
foo(f_c); // OH NO! Tries to print arr, but it has been deleted by previous call! Segmentation fault :(
return 0;
}
A few non solutions I should mention are:
Making freeOnDestroy::freeOnDestroy(const freeOnDestroy &src) explicit and private, but this seems to override T's constructor. I'd hoped it would try to implicitly convert it to T and use that as the template argument.
Assume foo receives a reference of its templated arguments (as in void foo(T &in): This is neither the case, nor desirable in some cases
Always explicitly template the call to foo, as in foo<C>(f_c): f_c itself may be templated, so it's hard to know to instantiate foo with C (yes, this could be done with creating multiple versions of foo, to remove the wrappers one by one, but I can't find a way of doing that without creating a different overload for each templated argument of foo).
In summary, my question is: Is there a clean(ish) method to ensure a base class will be casted to its superclass when resolving a template? Or, if not, is there some way of using SFINAE, by causing a substitution failure when the template argument is an instance of the wrapper class, and thus force it to use the implicit cast to the wrapped class (without duplicating each foo-like method signature possibly dozens of times)?
I presently have a work-arround that involves changes in the DSL, but I'm not entirely happy with it, and was curious if it was at all possible to design a wrapper class that works as described.
The problem here not when "wrapped class gets used as a member to a non-reference templated call".
The problem here is that the template wrapper -- and likely its superclass too -- has violated the Rule Of Three.
Passing an instance of the class as a non-reference parameter is just another way of saying "passing by value". Passing by value makes a copy of the instance of the class. Neither your template class -- nor its wrapped class, most likely -- has an explicit copy constructor; as such the copied instance of the class has no knowledge that it is a copy, hence the destructor does what it thinks it should do.
The correct solution here is not to hack something up that makes passing an instance of freeOnDestroy<T> by value end up copying T, rather than freeOnDestroy<T>. The correct solution is to add a proper copy-constructor and the assignment operator to both the freeOnDestroy template, and possibly any superclass that uses it, so that everything complies with the Rule Of Three.
You can use a properly defined detector and a sfinaed function, as it follows:
#include<iostream>
#include<type_traits>
template<class T>
class freeOnDestroy : public T {
using T::T;
public:
operator T&() const { return *this; }
~freeOnDestroy() { T::free(); }
};
template<typename T>
struct FreeOnDestroyDetector: std::false_type { };
template<typename T>
struct FreeOnDestroyDetector<freeOnDestroy<T>>: std::true_type { };
class C{
int * arr;
public:
C(int size){
arr = new int[size];
for (int i = 0; i < size; i++) arr[i] = i;
}
int operator[] (int idx) { return arr[idx]; }
void free(){ std::cout << "free called!\n"; delete []arr; }
};
class V{
int cval;
public:
V(int cval) : cval(cval) {}
int operator[] (int idx) { return cval; }
void free(){}
};
template<typename..., typename T>
std::enable_if_t<not FreeOnDestroyDetector<std::decay_t<T>>::value>
foo(T in) {
std::cout << "here you have not a freeOnDestroy based class" << std::endl;
}
template<typename..., typename T>
std::enable_if_t<FreeOnDestroyDetector<std::decay_t<T>>::value>
foo(T &in) {
std::cout << "here you have a freeOnDestroy based class" << std::endl;
}
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(c);
foo(v);
foo<C>(f_c);
foo(f_c);
foo(f_c);
return 0;
}
As you can see by running the example, free is called only once, that is for the freeOnDestroy created in the main function.
If you want to forbid definitely freeOnDestroy as a parameter, you can use a single function as the following one:
template<typename..., typename T>
void foo(T &in) {
static_assert(not FreeOnDestroyDetector<std::decay_t<T>>::value, "!");
std::cout << "here you have a freeOnDestroy based class" << std::endl;
}
Note that I added a variadic parameter as a guard, so that one can no longer use foo<C>(f_c); to force a type to be used.
Remove it if you want to allow such an expression. It was not clear from the question.
One solution, which, although a little ugly, seems to work, is to use an overloaded unwrapping method, such as:
template<typename T> T freeOnDestroyUnwrapper(const T &in){ return in; }
template<typename T> T freeOnDestroyUnwrapper(const freeOnDestroy<T> &in){ return in; }
template<typename T> T freeOnDestroyUnwrapper(const freeOnDestroy<typename std::decay<T>::type> &in){ return in; }
template<typename T> T& freeOnDestroyUnwrapper(T &in){ return in; }
template<typename T> T& freeOnDestroyUnwrapper(freeOnDestroy<T> &in){ return in; }
template<typename T> T& freeOnDestroyUnwrapper(freeOnDestroy<typename std::decay<T>::type> &in){ return in; }
Then, calls can be made using the unwrapper:
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(freeOnDestroyUnwrapper(c));
foo(freeOnDestroyUnwrapper(v));
foo<C>(freeOnDestroyUnwrapper(f_c));
foo(freeOnDestroyUnwrapper(f_c));
foo(freeOnDestroyUnwrapper(f_c));
return 0;
}
Or, to make this less verbose, we can alter foo so it does this for us:
template<typename T>
void _foo(T in){
for(int i = 0; i < 5; i++) cout << in[i] << ' ';
cout << '\n';
}
template<typename... Ts>
void foo(Ts&&... args){
_foo(freeOnDestroyUnwrapper(args)...);
}
And then call it as normal:
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(c);
foo(v);
//foo<C>(f_c); // This now doesn't work!
foo(f_c);
foo(f_c);
return 0;
}
This seems to work for any number of arguments foo may have (of different templates, if needed), and seems to behave appropriately when foos input is a reference (which does not occur in my context, but would be good for the sake of making this solution generic).
I'm not convinced that this is the best solution, or that it generalizes to every case, plus, having to double all declarations is a bit cumbersome, and opaque to most IDEs autocomplete features. Better solutions and improvements are welcome!

Is there a better/safe way to cast non-const reference of shared_ptr to a base class?

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;
}