template <class T>
class ListNode {
public:
T* data;
ListNode<T>* next;
}
Lets say I have got a list node template and somewhere in the code I want to get a copy of the data - meaning not a copy of a pointer to data (T*) but a new pointer (T*) which will point to another place in the memory which have the same information there.
How can I do it when using C++ templates? How can I copy (*data) if I don't know what is the type of T.
The compiler knows the type of T. What is does not know is how many instances of T are pointed to. In terms of getting a practical implementation, the short answer would be don't use pointer types. Use containers instead. Since you are copying the node data anyway the overhead is minimal. Explicit example below:
template <class T>
class ListNode {
public:
// use a vector as the container
std::vector<T> data;
ListNode<T>* next;
// initializer from pointer primitive
ListNode(const T* ps,size_t elements)
{
data.assign(ps,ps+elements);
}
// copy templated instance
ListNode(const ListNode& arg)
{
data = arg.data;
}
// assignment
ListNode& operator=(const ListNode& arg)
{
if (this != &arg)
{
data = arg.data;
}
return *this;
}
};
Actual usage would be similar to this:
{
const char* ps = "Hello World";
ListNode<char> ln1(ps,strlen(ps));
ListNode<char> ln2 = ln1;
}
You can, of course, get much more complicated solutions but they will all involve keeping track of the number of instances of type T to which your pointer points.
T has to be copy-constructable so that you can do
template <class T>
ListNode<T>::ListNode(const ListNode<T>& src)
{
...
// given a preexisting copy, src, create a new T to
// perform a copy
T* destT = new T(*srcT);
}
If T has a copy constructor, this will work. If it doesn't, the compiler will give you an error (probably a very cryptic one)
Use operator= or the copy constructor. It's standard practice that both of these will produce a copy of the object.
So, for example:
T *p = other_pointer;
*p = *data;
Or
T* copy = new T(*data);
When creating a copy of a templated type, practically you need not worry about the type as such and live that task on the copy constructor or assignment operator of that type:
template <class T>
class ListNode {
public:
T* data;
ListNode<T>* next;
T* getCopy() { new T(*data); } // get copy of "data"
};
Suppose you use this ListNode<T> for class A, then you can have a copy constructor defined for A (and assignment operator as well):
class A {
public:
A(const A& copy);
};
Now when ListNode<T>::getCopy() is called, it will call the copy constructor of A internally.
Related
For a user-defined allocator, the relation between the allocated-units must be constructed at the beginning, while the memory space for elements should be left uninitialized.
A simple demo:
template <typename T>
struct Node {
T _item;
Node* _prev;
Node* _next;
};
template <typename T, typename ParentAllocator>
class MyAllocator {
using Allocator = std::allocator_traits<ParentAllocator>::rebind_alloc<Node<T>>;
Allocator _allocator;
Node<T> _header;
/* ... */
public:
MyAllocator()
: _allocator()
{
_header._prev = &_header;
_header._next = &_header;
// leaving `_item` uninitialized
}
T* allocate(/*one*/) {
auto* newNode = _allocator.allocate(1);
newNode->_prev = &_header;
newNode->_next = _header._next;
// leaving `_item` uninitialized
/* ... */
return &(newNode->_item);
}
};
Node is not initialized, instead direct initialization for its members, though not for all.
My questions are:
Are _header and _next really partially initialized as expectations, even if the default constructor of T (both normal and explicit one) were deleted.
Have I implemented it properly?
If not, what's the right way?
You need to modify Node to make it default constructible, and you don't want to default construct T even if it has a default constructor. So you can replace T _item with:
std::aligned_storage<sizeof(T), alignof(T)> _item;
Or in C++23 because std::aligned_storage is deprecated:
alignas(T) std::byte _item[sizeof(T)];
That will give you the storage space you need, with appropriate alignment, and then you'll use placement new to construct T in that storage. You will also need to explicitly invoke ~T() before or during destruction of each Node.
Demo showing the basics, certainly not complete or tested: https://godbolt.org/z/bGaKWb3de
I am trying to implement a class that represents a doubly-linked list, and I have a function createNode() which returns a new Node (A templated class) with all its members initialized. This function is going to be used to create linked lists where the size is known, but no data has been passed to it. For most data types, this works. However, this does not work for classes without default constructors, since they cannot be initialized without parameters. Here is the minimal code that exhibits this:
class Test // A class without a default constructor
{
public:
Test(int value) : value_{ value } { };
private:
int value_;
};
template<typename T>
struct Node
{
Node* prev;
Node* next;
T value;
};
template<typename T>
Node<T>* createNode()
{
return new Node<T>{ nullptr, nullptr, T() }; // How do I change T() so
// that I can use classes
// without default constructors?
}
int main()
{
Node<Test>* testNode = createNode<Test>();
delete testNode;
}
Basically, my final goal is to be able to create a linked list which can hold uninitialized nodes while keeping track of which nodes are initialized or not. I remember reading in an old textbook of mine about a method for solving this problem that involves using allocators (Which are used for handling construction/destruction of objects), but I don't remember the exact technique at all. So how should I go about this?
Use std::optional<T> if you have access to C++17, or boost::optional<T> if you don't.
template<typename T>
struct Node
{
Node* prev;
Node* next;
std::optional<T> value; // or boost::optional<T> value;
};
template<typename T>
Node<T>* createNode()
{
return new Node<T>{ nullptr, nullptr, std::nullopt /* or boost::none */ };
}
If you don't have access to C++17 and don't want to include boost, you could roll your own optional template with something like this:
struct nullopt_t {};
nullopt_t nullopt;
template <typename T>
class optional
{
public:
template <typename... Args>
optional(Args&&... args)
: ptr{new ((void*)&storage) T(std::forward<Args>(args)...)}
{}
optional(nullopt_t)
: ptr{nullptr}
{}
~optional()
{
if (ptr) {
ptr->~T();
}
}
optional& operator=(T obj)
{
if (ptr) {
*ptr = std::move(obj);
} else {
ptr = new ((void*)&storage) T(std::move(obj));
}
return *this;
}
explicit operator bool()
{
return ptr != nullptr;
}
T& value()
{
if (!ptr) {
throw std::exception();
}
return *ptr;
}
// Other const-correct and rvalue-correct accessors left
// as an exercise to the reader
private:
std::aligned_storage_t<sizeof(T), alignof(T)> storage;
T* ptr;
};
Live Demo
You can use placement new to place the object later in a pre-allocated memory.
It's just about splitting the memory allocation from the construction of the objects. So you can declare a member in your Node that takes memory but do not construct object because it needs parameter. Later you can construct the object with the needed parameters but not allocate memory with new but use placement new to just call the constructor with memory already allocated within the Node.
So following is an example of a self-made std::optional. In n3527 you can find more details about std::optional.
#include <vector>
#include <functional>
#include <iostream>
#include <algorithm>
#include <string>
#include <memory>
using namespace std;
class Test // A class without a default constructor
{
public:
Test(int value) : value_{ value } { };
//private:
int value_;
};
template<typename T>
struct Node
{
Node* prev;
Node* next;
bool empty = true;
union {
T t;
} value; // Could be replaced with typename std::aligned_storage<sizeof(T), alignof(T)>::type value;
// need a constructor that inits the value union and activate a field
// Node()
~Node() {
if (!empty) {
value.t.~T();
}
}
template<typename... Args>
void setValue(Args... args) {
if (!empty) {
value.t.~T();
}
new (&value.t) T(std::forward<Args...>(args...));
empty = false;
}
T& getValue() {
// TODO:
if (empty) {
//throw
}
return value.t;
}
};
template<typename T>
Node<T>* createNode()
{
return new Node<T>{ nullptr, nullptr }; // How do I change T() so
// that I can use classes
// without default constructors?
}
int main()
{
Node<Test>* testNode = createNode<Test>();
testNode->setValue(42);
if (!testNode->empty) {
std::cout << testNode->getValue().value_;
}
delete testNode;
return 0;
}
Live Demo
With few small changes and with reinterpret_cass you can also use typename std::aligned_storage<sizeof(T), alignof(T)>::type value; - Live Demo
Allocators manage the memory and you will not be able include (aggregate) the object in your class and have to use pointers and second allocation except you use allocator to place the entire Node.
There are interesting presentation form John Lakos about allocators on YouTube - CppCon 2017 Local 'Arena' Memory Allocators part 1 and 2.
What you are asking is literally impossible -- to default construct an object without a default constructor.
Perhaps consider adding a T nodeValue parameter to createNode()? Or change the Node itself so that rather than holding an object, it holds a pointer to the object. That seems like a memory management nightmare, but it could work.
How would you perform a move operation on a class that uses unique_ptr? Wouldn't setting the unique_ptr to null cause deletion of the data? If I perform a copy through a list initializer of the unique_ptr like so, would the data be preserved or deleted?
template<typename T, typename A = std::allocator<T>>
class forward_list
{
...
private:
struct node
{
T data;
std::unique_ptr<T> next;
};
std::unique_ptr<node> root_;
std::unique_ptr<node> leaf_;
size_t count_;
const A& heap;
};
// Move constructor. Constructs the container with the contents of other using move semantics.
// If alloc is not provided, allocator is obtained by move-construction from the allocator belonging to other.
inline forward_list(forward_list&& other)
: root_(other.root_), leaf_(other.leaf_), count_(other.count_), heap(other.heap)
{
other.root_ = nullptr;
other.leaf_ = nullptr;
other.count_ = 0;
};
You need to move the pointer.
forward_list(forward_list&& other) :
root_(std::move(other.root_)),
leaf_(std::move(other.leaf_)),
count_(other.count_),
heap(other.heap)
{
// Do nothing
}
As an example, consider a simple data structure like a linked list. In C, it might look like:
struct Node
{
struct Node *next;
void *data;
};
void *getLastItem(struct Node*);
...
I'd like to have the same struct and functions, but with better type checking by declaring the type of the data field, which will always be a pointer to something. An example use:
Node<Thing*> list = getListOfThings();
Thing *t = list->data;
t = getLastItem(list);
...
But I don't want to generate an implementation for every type of pointer, as happens with a normal template. In other words, I want something more like a generic or parametric type from Java, ML, and other languages. I just tried the code below as a test. The untyped C-like part would eventually go in a implementation file, while the template and function declarations would be in the header file. I'm assuming they would be optimized away and I'd be left with machine code that is about the same as the C version, except it would be type-checked.
But I'm not great with C++... Is there a way to improve this, or use more idiomatic C++, perhaps template specialization?
#include <stdio.h>
struct NodeImpl
{
NodeImpl *next;
void *data;
};
void *getLastItemImpl(NodeImpl *list)
{
printf("getLastItem, non-template implementation.\n");
return 0; // not implemented yet
}
template <typename T>
struct Node
{
Node<T> *next;
T data;
};
template <typename T>
T getLastItem(Node<T> *list)
{
return (T)getLastItemImpl((NodeImpl*)list);
}
struct A { };
struct B { };
int main()
{
Node<A*> *as = new Node<A*>;
A *a = getLastItem(as);
Node<B*> *bs = new Node<B*>;
B *b = getLastItem(bs);
}
This is exactly what Boost.PointerContainer does, check its implementation. Basically what it does is implement the specialization for void*, and have any other implementation forward to it static_casting the parameters in and out.
struct Node
{
struct Node *next;
void *data;
};
void *getLastItem(struct Node*);
...
This is common for C, but not for C++. In C++ it usually looks like this:
template<typename T>
struct Node
{
struct Node *next;
T data;
};
T& getLastItem(const Node&);
...
Note the important difference -- the C version has another level of indirection in order to share implementations, while the C++ version need not do this. This means the C version has another n dynamic memory allocations, where n is the number of items in the list. Given that each allocation usually requires obtaining a global lock, often has at least 16 bytes of overhead per allocation, as well as all the overhead the memory manager brings to the party, the advantage of the C++ version is not insignificant, particularly when you include things like cache locality in the considerations.
Put another way, for Node<int>, the C++ version stores an int, while the C version stores an int *, along with a dynamic allocation for the int.
This of course discounting that a linked list is a horrendous data structure 90% of the time.
If you must use a linked list, and if you must use dynamic allocation for the data members, then your idea of "replace the pointers with void*s" is not unreasonable. However, if you have access to a C++11 compiler (VS2010, recent GCC versions, etc.), you should put in an assert that you depend on T being a pointer type, using std::is_pointer and static_assert, and you should use static_cast rather than C-style casts in your interface methods. The C style cast would let someone do Node<SomeTypeBiggerThanVoidPtr>, and it would compile, but explode at runtime.
As the other answers and comments said, use std::forward_list, or another existing library. If you refuse, this is more like I would do:
#include <stdio.h>
struct NodeImpl
{
NodeImpl *next;
void *data;
public:
// we have pointers, so fulfill the rule of three
NodeImpl() : next(NULL), data(NULL) {}
~NodeImpl() {}
NodeImpl& operator=(const NodeImpl& b) {next = b.next; data = b.data; return *this;}
// This function now a member. Also, I defined it.
void* getLastItem()
{
if (next)
return next->getLastItem();
return data;
}
void* getData() {return data;}
void setData(void* d) {data = d;}
};
// the template _inherits_ from the impl
template <typename T>
struct Node : public NodeImpl
{
Node<T> operator=(const Node<T>& b) {NodeImpl::operator=(b);}
// we "redefine" the members, but they're really just wrappers
T* getLastItem()
{ return static_cast<T*>(NodeImpl::getLastItem());}
T* getData() {return static_cast<T*>(NodeImpl::getData());}
void setData(T* d) {NodeImpl::setData(static_cast<void*>(d));}
//or, if you prefer directness...
operator T*() {return static_cast<T*>(NodeImpl::getData());}
Node<T> operator=(T* d) {NodeImpl::setData(static_cast<void*>(d));}
};
struct A { };
struct B { };
int main()
{
Node<A> as; //why were these heap allocated? The root can be on the stack
A *a = as.getLastItem();
Node<B> bs; //also, we want a each node to point to a B, not a B*
B *b = bs.getLastItem();
B* newB = new B;
bs = newB; //set the data member
newB = bs; //read the data member
}
http://ideone.com/xseYk
Keep in mind that this object doesn't encapsulate next or data really, so you have to manage all of that yourself.
I have a generic list with a template
template<class t>
class GenericList {
//the data is storeed in a chained list, this is not really important.
struct c_list { t data; c_list* next; ...constructor... };
public:
bool isDelete;
GenericList() : isDelete(false) {...}
void add(t d) {
c_list* tmp = new c_list(d, first->next);
//this is not really important again...
}
~GenericList() {
c_list* tmp = first;
c_list* tmp2;
while(tmp->next!=NULL) {
if (isDelete) { delete tmp->data; } //important part
tmp2=tmp->next;
delete tmp;
tmp=tmp2;
}
}
};
The important part is the isDelete
This is only a sample code
I need this because I want to store data like this:
GenericList<int> list;
list.add(22);list.add(33);
and also
GenericList<string*> list;
list.add(new string("asd")); list.add(new string("watta"));
The problem if I store only <int> the compiler said that I cannot delete non pointer variables, but I don't want to in this case. How can I solve this?
when I store <int*> there is no compiler error...
Without changing much your code, I would solve your problem as
template<class t>
class GenericList
{
//same as before
//add this function template
template<typename T>
void delete_if_pointer(T & item) {} //do nothing: item is not pointer
template<typename T>
void delete_if_pointer(T* item) { delete item; } //delete: item is pointer
~GenericList() {
c_list* tmp = first;
c_list* tmp2;
while(tmp->next!=NULL) {
delete_if_pointer(tmp->data); // call the function template
tmp2=tmp->next;
delete tmp;
tmp=tmp2;
}
}
};
EDIT: I just noticed that #ildjarn has provided similar solution. However there is one interesting difference: my solution does NOT require you to mention the type of data when calling the function template; the compiler automatically deduces it. #ildjarn's solution, however, requires you to mention the type explicitly; the compiler cannot deduce the type in his solution.
I would create a nested struct template inside your class to help:
template<typename U>
struct deleter
{
static void invoke(U const&) { }
};
template<typename U>
struct deleter<U*>
{
static void invoke(U* const ptr) { delete ptr; }
};
Then change the line that was using isDelete from
if (isDelete) { delete tmp->data; }
to
if (isDelete) { deleter<t>::invoke(tmp->data); }
delete on an int makes a program ill-formed, so the compiler will reject it, even though the delete would never be reached.
What you want is only possible if you switch from "bare" pointers to smart pointers such as unique_ptr or shared_ptr; those handle memory management for you, without explicit delete.