1

So I am trying to make a linked list that can contain any data type at the same time. The list contains Element objects:

struct Element {
  void* data;
  Element* next;

  Element(const void* content, Element* next_ele) {
    next = next_ele;
    data = new void;  // this doesn't work
    (*data) = (*content)
  }
};

The reason I have to allocate memory for data is because if I just assign data = content, if *content is destroyed (such as when leaving a local function), *data will also be destroyed. That means if I add some elements to the list inside a function, those elements will disappear from the list when the function exits. The example is below:

// in List.cpp
List::add(void *content) {
    // for this question, ignore the case when list is empty 
    Element *ele = new Element(content, nullptr); 
    last.next = ele
    last = ele
}


// main.cpp
List myList;

void addEle() {
    int a; double b; char c;
    myList.add(&a); myList.add(&b); myList.add(&c);
}

int main()
{
    myList = newList();
    addEle();
}

When addEle() exits, variables a, b, c doesn't exist anymore. So the content of the list is nonsense.

So how can I allocate memory of void type in C++ to solve this problem? If I can't, is there any solution (except template) so that when I leave a local function, the content of a list isn't changed ?

Thank you for your help.

Edit 1: I can't use template because using template means each list object can only contain 1 data type. But I want to do something like myList.add(1), myList.add(3.5), myList.add('c'), myList.add(student), etc

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
Duke Le
  • 332
  • 3
  • 14
  • 3
    Why not use templates instead of void pointers? – Paul Rooney Dec 13 '19 at 05:40
  • `new void` does not declare a new void pointer. – David C. Rankin Dec 13 '19 at 05:43
  • 1
    what would one do with a `void`? Didn't you see [what it did to Fantasia](https://en.wikipedia.org/wiki/The_Neverending_Story)? – user4581301 Dec 13 '19 at 05:45
  • Because if I use template, each list can only contain 1 datatype of that template. But I wish the list to be able to contain anything (int, double, char*, objects, etc) – Duke Le Dec 13 '19 at 05:45
  • Say `void *f = new void*; char foo[] = "hello"; f = foo; std::cout << (char *)f << '\n';` (note, you cannot call `delete` type `void*` and not when it points to something not allocated with `new`) – David C. Rankin Dec 13 '19 at 05:47
  • 1
    @user3192711: How would you be able to interact with a linked list of types that you don't know what they are? How would you know which ones to convert back to `int` or `double` or `char` or whatever? C++ is not C#; [`void*`s don't know what they used to point to](https://stackoverflow.com/q/8530080/734069). – Nicol Bolas Dec 13 '19 at 05:49
  • When you have a `void *`, you can point it at anything. That's the blessing and the curse. You better remember what you stored or... Well there's no way to predict the or else. – user4581301 Dec 13 '19 at 05:50
  • It's my understanding that the `new` operator in C++ does two things: 1. Allocate memory for a object instance of a specific `class`, and 2. Call the appropriate constructor for the object being created. Since `void` is a primitive type, it does not have a constructor, and thus, I think, calling `new` to create a `void*` doesn't seem to apply in this case. – jwir3 Dec 13 '19 at 05:51
  • 2
    I makes much more sense in C than it does in C++. – David C. Rankin Dec 13 '19 at 05:51
  • So it is not possible for general-type linked list to exist in C++? I mean something similar to Python list where you can do this: a = []; a.append(1); a.append(0.5); a.append([1 2 3]); a.append("Hello") – Duke Le Dec 13 '19 at 06:02
  • Ah okay, so it means doing things like this is not possible at worst and not advisable at best. I'm just trying to test if this is possible or not. Thank you – Duke Le Dec 13 '19 at 06:12
  • No worries. I put this in the inadvisable camp. You can do it, but you need extra book-keeping. If you keep the number of possibilities down, you could have a `std::pair` of a enum that identifies the type of the data ( the book-keeping) and the `void*`. In C++17 you'd probably use a std::variant`. – user4581301 Dec 13 '19 at 06:17
  • @user4581301 or maybe a simple `std::tuple`. Depends on if the types are known at compile time. – Aykhan Hagverdili Dec 13 '19 at 06:22

2 Answers2

0

Leaving aside the question of why, std::any seems like the solution you're looking for.

#include<any>

struct A
{
    std::any data;
    A() = default;
};


int main()
{
    A a;
    a.data = "Hello World\n";
    a.data = 1;
    a.data = 2.5f;
    a.data = 'B';
}
Rish
  • 583
  • 1
  • 8
  • 18
0

Templates are the solution you are looking for. You can store any type in this way:

struct Element {
  void* data;
  Element* next;

  template <typename T>
  Element(const T* content, Element* next_ele) {
    next = next_ele;
    data = new T{ *content };
  }
};

Also see this: Is it safe to delete a void pointer?

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
  • Problem is the asker can't stick `A`s in the same list as a `B` without adding in another trick. How the asker's going to tell `A`s from `B`s, smurfed if I know, but hey. I don't have to debug it. – user4581301 Dec 13 '19 at 06:03
  • 1
    @user4581301 you mean how they are going to dereference pointers in the list? I have no idea, they didn't ask that in the question. They also have to find a way to call destructors, because deleting a `void *` doesn't call the destructors. – Aykhan Hagverdili Dec 13 '19 at 06:08
  • 1
    From the comments, it seems that there's no practical reason to do this because I don't have the way to dereference them anyway. I asked the question to learn "how", but I guess the correct answer is "don't do it in the first place". Thanks everyone! – Duke Le Dec 13 '19 at 06:16
  • @user3192711 `std::vector` or `std::list` is the closest you can get to a Python list with the standard library. But even then you have to find a way to store the type information to use `std::any_cast`. You may just need [std::tuple](https://en.cppreference.com/w/cpp/utility/tuple). – Aykhan Hagverdili Dec 13 '19 at 06:20