C++ Reference Handle - c++

concerning code from Accelerated C++:
template <class T> class Ref_handle {
public:
Ref_handle(): refptr(new size_t(1)), p(0) { }
Ref_handle(T* t): refptr(new size_t(1)), p(t) { }
Ref_handle(const Ref_handle& h): refptr(h.refptr), p(h.p)
{
++*refptr; //???
}
~Ref_handle();
private:
T* p;
size_t* refptr;
};
I understand the principle of handle, but I don't understand why compiler allows this kind op copy constructor. It copies pointers, but since it's pointing to a same size_t object, it's actually changing its value, although we "promised" with const that we won't change it.

Related

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.

Capture handle by reference or by value to class template ctor

Consider a tempalted class InputBuffer:
template<class Source, size_t Capacity>
class InputBuffer
{
public:
explicit InputBuffer(Source src);
int getchar();
private:
std::byte const* m_read_ptr;
std::byte const* m_last_valid;
Source m_src;
std::array<std::byte, Capacity> m_data;
void fetchAndResetPointers();
};
Question: Should the constructor instead accept src as a reference and store a pointer instead of taking it by value? It is very likely that the caller expect reference semantics here. However, it is also possible that Source already is some kind of pointer, and then, taking src by reference and storing a pointer would lead to an unnecessary indirection. If not passing by reference, the user can use std::ref if needed.
This class is no good as is in my opinion - you assume that "source" requires an m_read_ptr, m_last_valid and m_data as context. However, if it's a file, for instance, it requires non of these. Instead, rewrite this class as an interface, or better yet, don't create a generic class at all and use templates when handling "sources", example in pseudo-code:
class FileBuffer {
public:
explicit FileBuffer(File* f) : m_f(f) {}
int getchar() { return read(f, 1); }
private:
File* m_f;
};
template<class T>
void print_from_buffer_to_stdout(T& buf) {
std:: cout << buf.getchar();
}
int main() {
FileBuffer f = get_file_buffer(); // somehow
print_from_buffer_to_stdout(f);
}

Cannot convert from std::shared_ptr<_Ty> to std::shared_ptr<_Ty>

I am getting the following error:
error C2440: 'static_cast' : cannot convert from 'std::shared_ptr<_Ty>' to 'std::shared_ptr<_Ty> stack\genericstack.h 36 1 Stack
GenericStack.h
#ifndef _GENERIC_STACK_TROFIMOV_H_
#define _GENERIC_STACK_TROFIMOV_H_
#include <memory>
class GenericStack {
struct StackNode {
std::shared_ptr<void> _data;
StackNode* _next;
StackNode(const std::shared_ptr<void>& data, StackNode* next)
: _data(data), _next(next) {
}
};
StackNode* _top;
GenericStack(const GenericStack&);
GenericStack& operator=(const GenericStack&);
protected:
GenericStack();
~GenericStack();
void push(const std::shared_ptr<void>&);
void pop();
std::shared_ptr<void>& top();
bool isEmpty() const;
};
template <class T>
class TStack: private GenericStack {
public:
void push(const std::shared_ptr<T>& p) { GenericStack::push(p); }
void pop() { GenericStack::pop(); }
std::shared_ptr<T> top() { return static_cast<std::shared_ptr<T>>(GenericStack::top()); }
bool empty() const { return GenericStack::isEmpty(); }
};
#endif
GenerickStack.cpp
#include "GenericStack.h"
GenericStack::GenericStack()
:_top(0) {
};
GenericStack::~GenericStack() {
while(!isEmpty()) {
pop();
}
};
void GenericStack::push(const std::shared_ptr<void>& element) {
_top = new StackNode(element, _top);
}
std::shared_ptr<void>& GenericStack::top() {
return _top->_data;
}
void GenericStack::pop() {
StackNode* t = _top->_next;
delete _top;
_top = t;
}
bool GenericStack::isEmpty() const {
return !_top;
}
Main.cpp
#include <iostream>
#include "GenericStack.h"
int main() {
TStack<int> gs;
std::shared_ptr<int> sh(new int(7));
gs.push(sh);
std::cout << *gs.top() << std::endl;
return 0;
}
Why am I getting the error?
I would expect the cast to happen successfully, since with raw pointers I always can case from void* to the real type pointer.
What I want to do here is to create a stack template. But I am trying to reuse as much code as I can, so that templated classes would not swell too much.
Thank you.
You get that error because static_cast requires the types from and to to be convertible. For shared_ptr that will hold only if c'tor overload 9 would participate in overload resolution. But it doesn't, because void* is not implicitly convertible to other object pointer types in C++, it needs an explicit static_cast.
If you want to convert shared pointers based on static_casting the managed pointer types, you need to use std::static_pointer_cast, that is what it's for.
So after plugging that fix
std::shared_ptr<T> top() { return std::static_pointer_cast<T>(GenericStack::top()); }
Your thin template wrapper will build fine.
Take a look at the list of constructors for shared_ptr. You are trying to use overload 9, more specifically the template overload with Y = void and T = int. However, this template overload doesn't participate in overload resolution, because void* is not implicitly convertible to int*. In other words, you cannot convert, even explicitly, shared_ptr<void> to shared_ptr<T> if you cannot implicitly convert void* to T*.
Why not use a template in the first place (move GenericStack functionality into TStack), instead of trying to deal with void*?
But I am trying to reuse as much code as I can, so that templated classes would not swell too much.
By "swell", I assume you mean the template solution would generate too many instances? Do you have any reason to believe that it would indeed be too many?

C++ safety of using `new char[size]` for memory allocation and deallocation for arbitrary data

I have the following functions:
private:
static char* new_data(std::size_t size) { return new char[size]; }
template<typename T> static char* new_data(T& value) { return reinterpret_cast<char*>(new (new_data(sizeof(T))) T(value)); }
template<typename T> static char* new_data(T&& value) { return reinterpret_cast<char*>(new (new_data(sizeof(T))) T(value)); }
static void delete_data(char* data) { return delete[] data; }
(Note: T is any type, except it won't overload any form of new or delete)
These functions are only used as part of a RAII-like struct, so there should not been any memory leaks caused by using them.
I am concerned about the safety of this, specifically with regards to alignment (as an array suitably aligned for char might not be properly aligned for T).
My questions is this:
What can I do to make my code perfectly safe? If it already is, why is it?
EDIT:
I am also assuming here that 'T' has a trivial destructor (well all the types I'm currently using do...)
Also with regards to new_data(std::size_t size)` I am only using it when I am going to manual construct the values (because the corresponding 'type' is to be generated at run time, which will not require allignment)
EDIT: Telling me to use smart pointers is not an answer just because using someone else's code could make my code smaller, that does not make it better (primarily due to efficiency and ease of use).
EDIT: I have decided to use the following modified code:
struct Constant
{
template<typename T, typename... Targs> static Constant&& construct(Targs... args...)
{
return Constant(sizeof(T), new(new char[sizeof(T)]) T(args...));
}
template<typename T> static Constant&& construct_default()
{
return Constant(sizeof(T), new(new char[sizeof(T)]) T);
}
template<typename T, typename... Targs> static Constant&& construct_list(Targs... args...)
{
return Constant(sizeof(T), new(new char[sizeof(T)]) T{args...});
}
Constant()
: Constant(0, nullptr, nullptr) { }
explicit Constant(std::size_t size, Syntax::Expression* creator = nullptr)
: Constant(size, new char[size], creator) { allocate(); }
Constant(const Constant& c)
: Constant(c.size_value, c.data_pointer, c.creator) { allocate(); }
Constant(Constant&& c)
: Constant(c.size_value, c.data_pointer, c.creator) { c.data_pointer = nullptr; }
private:
std::size_t size_value = 0;
char* data_pointer = nullptr;
public:
Syntax::Expression* creator = nullptr;
std::size_t size() const { return size_value; }
template<typename T = char*> T data() { return reinterpret_cast<T>(data_pointer); }
template<typename T = const char*> T data() const { return reinterpret_cast<T>(data_pointer); }
template<typename T> Constant&& copy() const
{
return Constant(size_value, new (new char[sizeof(T)]) T(*reinterpret_cast<T*>(data_pointer)), creator);
}
template<typename T> Constant&& copy(Syntax::Expression* e) const
{
return Constant(size_value, new (new char[sizeof(T)]) T(*reinterpret_cast<T*>(data_pointer)), e);
}
Constant&& raw_copy() const
{
return Constant(size_value, std::memcpy(new char[size_value], data_pointer, size_value), creator);
}
Constant&& raw_copy(Syntax::Expression* e) const
{
return Constant(size_value, std::memcpy(new char[size_value], data_pointer, size_value), e);
}
Constant& operator =(const Constant& c)
{
deallocate();
size_value = c.size_value;
data_pointer = c.data_pointer;
creator = c.creator;
allocate();
return *this;
}
Constant& operator =(Constant&& c)
{
deallocate();
size_value = c.size_value;
data_pointer = c.data_pointer;
creator = c.creator;
c.data_pointer = nullptr;
return *this;
}
~Constant() { deallocate(); }
private:
Constant(std::size_t size, void* data, Syntax::Expression* creator = nullptr)
: size_value(size), data_pointer(reinterpret_cast<char*>(data)), creator(creator) { }
static std::map<void*, std::size_t> allocation_table;
void allocate() const
{
if (data_pointer == nullptr)
return;
if (allocation_table.count(data_pointer) == 0)
allocation_table[data_pointer] = 1;
else allocation_table[data_pointer]++;
}
void deallocate() const
{
if (data_pointer == nullptr)
return;
if ((allocation_table[data_pointer] -= 1) == 0)
{
delete[] data_pointer;
allocation_table.erase(data_pointer);
}
}
};
std::map<void*, std::size_t> Constant::allocation_table = {};
Thank you to everyone who helped me. Though my question was never actually fully answered, based on my reading on http://en.cppreference.com/w/cpp/memory/new/operator_new and http://en.cppreference.com/w/cpp/language/new, I am pretty sure my code is safe (though not certain). Also I may have the ... syntax completely wrong, but I should find out when I actually try and compile it (and use it).
You're basically reinventing:
T* t = new T(value);
T* u = new T(std::move(value));
except it's much less functional, because I can't use any other constructor of T besides copy and move. Not even default! (Note also that your second constructor is incorrect - you should forward from value, not copy it, and having a forwarding-reference constructor makes having an lvalue reference constructor redundant. Also you want to create a decay_t<T>, not a T - because T can be a reference type).
And it's much less safe because... well, what do I do with t and u at the end? You would call delete_data(). That frees the memory, but it doesn't destroy the objects. You're missing a destructor call. delete t does both for you.
Basically, this gives you no advantage and a few important disadvantages over just normal raw new and delete. And modern C++ has tools that have advantages over those: smart pointers. When in doubt, use those instead.
It's also worth pointing out, that these two overloads:
static char* new_data(std::size_t size);
template<typename T> static char* new_data(T&& value);
do wildly different things in a way that could be very confusing. new_data(42) allocates 4 bytes and placement-news 42 into there. new_data((size_t)42) allocates 42 bytes. That's just very error prone.
You could allocate std::max_align_t instead of char, in order to have safely-aligned objects.
However, this doesn't address the issue that neither constructors, nor destructors, are going to get invoked here.
RAII is already a solved issue. There is no reason to reinvent this wheel, in some odd manner. Use containers, and/or std::shared_ptr, and your code will be RAII-safe, by default.

How to pass data to a templated collection

I have to write a generic data structure that resembles a C++ vector as part of an assignment.
This is my idea for the Vector:
template<typename T>
class MyVector {
private:
T* data_;
size_t size_;
public:
MyVector();
MyVector(const MyVector &otherVector);
// which one should I use?
add(const T& value);
add(T value);
~MyVector();
};
Now I wonder how to pass values to the methods. Coming from Java I am a bit overwhelmed. In Java you wouldn't hesitate and pass the value by reference, the GC would never delete the object if it is still referenced.
In C++ you would create a mess if you would pass by reference considering code like this:
void myFunction(MyVector &myVector) {
int a = 5;
myVector.add(a);
}
int main() {
auto vector = MyVector<int>();
myFunction(vector);
// now the vector contains a reference to
// something that doesn't exist anymore.
}
How do you solve this problem? Would you just pass by reference and create a copy or do you pass by value (which creates a copy for you)
Looking at the C++ std::vector interface I see that they use references.
I just don't see the value of passing by reference if you have to create your own copy.
add(const T& value) is ok, you just should be sure that there is properly defined assign operator for T. So, the implementation will be:
void Add(const T& value) {
if (m_size == m_maxSize) realloc(); // stuff to have enough space
m_data[m_size++] = value; // here copy is creating
}
default impl of assign operator just byte-copy fields of class, it is not always correct.
Other solution, if you want more java-style semantic, is to make T = shared_ptr<YourType> or T = YourType*
The latter is rather difficult because require skill of manual lifetime control, so is undesirable for c++ beginners.
void myFunction(MyVector<shared_ptr<X>> & myVector)
{
shared_ptr<X> x(new X(...));
myVector.add(x);
}
works similar to references in Java.
Other way, that was used in old times:
template<typename T>
class MyVector {
private:
T** data_; // now you have array of pointers, so should be careful
....
add(T* value);
....
}
void myFunction(MyVector<X> & myVector)
{
X * x = new X(...);
myVector.add(x); // now x belongs to myVector and it should handle its lifetime
}