-1

Sometimes I have a problem and see 3 ways of implementing the solution. I want to know when to use which of these 3 different implementations. Below there are some exsamples, to see what I mean. I also wrote some pros/kontras which I think is correct. If something seems to be wrong, then please tell me and I'll change that.

void* example:

void method(void* value)
{
    //save value as member
}

pro void*:

void* can save every type and you don't have to use templates (in headers).

kontra void*:

-when you have a list of void* you can store in index[1] another type than in index[2] which is critical, because you don't know which type it is. But with dynamic_cast you can check if you can cast it to the type or not.

-when you have a void* list with entities of the same class which have 2 variables, you can not sort by variable1 / variable2 without casting it back to the original class.

Extension exsample:

Creating a new class and extent it on another class:

class CTestClass
{
    void Method1();
};

class CTest2 : CTestClass
{
    //use somehow the method
};

std::vector<CTestClass> list;

pro Extension:

this way of implementing a class can be usefull, if you need a method which is in every object you need. For example you want to sort by a variable. In such a method you can make the compare.

kontra Extension:

much effort

exsample template:

template <class T>
class CTest
{
     //do some stuff
};

pro template:

in a template list, you can not add different types at the same time.

kontra template:

when you have a template list of type T and T has for exsample 2 variables. You can not say: sort by variable1 or variable2 because you can not get into the class T.

As far as I know: you have to implement the template into the header file, which is ugly to see.

I hope everyone understands what I mean. Is void* a good way to program? Can I write templates also in .cpp files? What do you think when to use which of this techniques? Is there some kind of rule?

Thomas
  • 2,093
  • 3
  • 21
  • 40
  • 2
    Using void* is the mostly the worst option you can take. Go with 2 or 3 depending on what you need. Consider that it is absolutely valuable to get compiler errors, if a wrong type is used. With the void solution, you always need to check it dynamically, which is effort and error-prone. – tangoal Jun 30 '18 at 19:29
  • You for sure can sort the list by `variable1` or `variable2` why shouldn't that be possible, is like [Sorting a vector of custom objects](https://stackoverflow.com/questions/1380463)? – t.niese Jun 30 '18 at 19:31
  • @tangoal thanks for the hint, I wonder, because in my old company they are using void* a lot – Thomas Jun 30 '18 at 19:32
  • 2
    I think you cannot do type checking for void*. Plus it is easy to make mistakes with void*. For extension you can only use user defined types as otherwise it would be difficult to make it reusable. As for C++11 you should definitely use templates. They are the recommended technique and you will get support to maintain your code. So templates I would say is the way to go. – Volt Jun 30 '18 at 19:34
  • 2
    @Thomas: in C world it is used often for very generic libraries. If you use these libraries, then you can't avoid it. However, in C++ it can be done "better" (more readable, less error-prone). There are maybe embedded environments, which force you to use void* too. But if you don't have such constraints, then I would always recommend to avoid void*. – tangoal Jun 30 '18 at 19:37
  • 1
    @tangoal Yeah. Certain libraries or hardware specific APIs to read from and to write to memory banks force using void*. +1 – Attersson Jun 30 '18 at 19:38
  • 1
    @Volt: You are right. You can't do it with the C++ language. You need to implement something peculiar, which is error-prone like you indicated. – tangoal Jun 30 '18 at 19:39
  • so in future, I will avoid void pointers. Thanks a lot! this was really helpful =) – Thomas Jun 30 '18 at 19:42
  • 1
    Yes if you are unsure, definitely avoid them. – Attersson Jun 30 '18 at 19:44

1 Answers1

2

The statement below is incorrect

pro void*:

void* can save every type and you don't have to use templates (in headers).

Templates haver their closest equivalent in cross macros and not in void pointers, but exist for a different set of purposes than the mere polymorphism afforded by void pointers. Using void pointers in no way substitutes templates.

While modern programmers might not recommend about using void pointers, complaining about the (true!) potential dangers afforded, old school C-style code certainly has a use for them and this is the reason they exist. Pairing the benefits gained from void pointers with the tradeoff in performance by the C++ dynamic cast, would simply spoil the choice.

Void pointers just exist to offer limitless flexibility at managing memory when you know what you are doing and should be used only in that case. There is no comparison between them and templates.

A method that takes a void * argument should only exist when:

  • Case 1: The size of the passed data is known and the argument is considered as raw data. It makes no difference what that data is.

  • Case 2: The size of the passed data is known and you plan to convert it to a pointer of the appropriate type later (for example by some parsing, enumeration policy, known type, etc) but in order to go through some general purpose functions, libraries, APIs, you must convert it to known-length void* inbetween.

Attersson
  • 4,755
  • 1
  • 15
  • 29
  • I know, if you have a template class and you create an object of lets say "int" and one object with "float", then the code gets copied, so after compiling, there are 2 classes (one with "int" and one with "float") that is not the same behavior than void* but for outsiders it looks like the same... – Thomas Jun 30 '18 at 19:45
  • It would be more correct to say the compiler makes 2 template resolutions. That way you have 2 overloads for that function that work with int and float. This is 100% different than a function which takes ANY argument as with void *. By managing size, if this is enough to know what your function will be doing, you can still have a use for the void * version – Attersson Jun 30 '18 at 19:47
  • I edited my answer, please take a glance at the 2 cases. – Attersson Jun 30 '18 at 20:00