0

I am trying to make void* to hold a value (to avoid default constructor calling).

I want to:-

  • copy K to void* e.g. K k1; --> void* raw=k1;
  • copy void* to K e.g. void* raw; --> K k2=raw;
  • try not to break destructor and causes memory leak
  • don't use any dynamic allocation (heap, performance reason)

Here is what I tried:-

class K{
    public: std::string yes="yes"   ;
};

int main() {
    //objective:  k1->raw->k2  , then delete "raw"
    void* raw[sizeof(K)];        //<--- try to avoid heap allocation
    K k1;
    static_cast<K>( raw)=k1;     //<--- compile fail
    K k2= static_cast<K>( raw);
    std::cout<<k2.yes;           //test
    static_cast<K&>(raw)::~K();  //mimic destructor
    return 0;
}

Question: Please provide a valid code that demonstrate a correct way to do this.

I found how to use placement new (https://stackoverflow.com/a/4756306/3577745 ), but not found how to use void* for a variable that is not an array.

C++ is new for me.

Edit :
I am writing a very custom collection (array).
Each element is encapsulated in a custom structure KCap kcap(with hold only 1 element, i.e. K).
Thus, I have to declare K k as a field of the encapsulator KCap.
However, I want to avoid default constructor of K, so I think void* can solve my issue.

Community
  • 1
  • 1
javaLover
  • 6,347
  • 2
  • 22
  • 67
  • 1
    This smells like you have another problem that you think *this* will solve. So why not ask about *that* instead? – StoryTeller - Unslander Monica Nov 15 '16 at 08:30
  • The variable `raw` is an *array* of pointers, not a single untyped object. For that an array of `char` is needed, together with placement `new`. – Some programmer dude Nov 15 '16 at 08:30
  • What you are trying to do doesn't make sense. A `void *` is used to hold an arbitrary type of pointer, not an arbitrary type of other object. – davmac Nov 15 '16 at 08:30
  • I think I can hold anything with `void *` even the thing is `value`. Do I misunderstand? I remembered I can do it for placement new. – javaLover Nov 15 '16 at 08:31
  • @javaLover you can hold any type of _pointer_ in a `void *`, not any type of value. But in general you should avoid the use of `void *` anyway. – davmac Nov 15 '16 at 08:32
  • Are you working with passing data to CWinThread? I face a similar situation. – khôi nguyễn Nov 15 '16 at 08:32
  • 2
    Yes you are misunderstanding. A `void*` variable can hold a *pointer* to anything. – Some programmer dude Nov 15 '16 at 08:32
  • I am writing a very custom collection (array). Each element is encapsulated in a custom structure (with hold only 1 element, i.e. `K`). So I have to declare `K k`. But I want to avoid default constructor of `K`, so I think `void*` can solve my issue. – javaLover Nov 15 '16 at 08:33
  • 2
    Then you need an array of `char`, i.e. `char x[some_size]`. And you need to use placement `new` to create the objects. – Some programmer dude Nov 15 '16 at 08:36
  • @Some programmer dude Thank a lot! I think your solution is correct, I will try. – javaLover Nov 15 '16 at 08:37
  • Also you won't get around executing constructors and destructors (thank goodness); plus, chances are that the `string` member in your class performs a dynamic allocation anyway! Another important issue is that the char array memory in the presented solutions has automatic storage duration and is as such unsuited to hold objects with dynamic storage duration which are supposed to survive the function call. (Sure, if it's in `main()` it exists until `main()` ends; but (1) code gets executed before and after that; and (2) you may be tempted to move it into a different function. Make it static. – Peter - Reinstate Monica Nov 15 '16 at 08:58
  • @Peter A. Schneider I accept that `string` is a bad example. XD – javaLover Nov 15 '16 at 09:01

1 Answers1

3

What you are trying to do doesn't make sense. A void * is used to hold an arbitrary type of pointer, not an arbitrary type of other object. If you want to use storage for an arbitrary object type, use a char[].

Other problems with your code include that you need to ensure correct alignment of the raw storage, use reinterpret_cast to a reference rather than static_cast to a non-reference, your in-place destructor call syntax is wrong, and that you don't construct the K object in the "raw" storage. Here's a corrected version:

#include <string>
#include <iostream>

class K{
    public: std::string yes="yes"   ;
};

int main() {
    //objective:  k1->raw->k2  , then delete "raw"
    alignas(alignof(K)) char raw[sizeof(K)];        //<--- try to avoid heap allocation
    K k1;
    new (reinterpret_cast<K *>(&raw)) K(k1);     //<--- compile now succeeds :)
    K k2= reinterpret_cast<K &>(raw);
    std::cout << k2.yes << std::endl;           //test
    reinterpret_cast<K&>(raw).K::~K();  // call destructor
    return 0;
}
davmac
  • 20,150
  • 1
  • 40
  • 68
  • You should remove the "compile fail" comment ;-). Unless it fails.# – Peter - Reinstate Monica Nov 15 '16 at 08:55
  • @davmac Do you think an answer (similar to yours) in another question http://stackoverflow.com/a/15343/3577745 suffer the mentioned alignment issue? – javaLover Nov 15 '16 at 08:56
  • 1
    @javaLover I _think_ because it allocates the `char` storage using `new`, it is ok; i.e. that `new` allocates storage suitably aligned for any object. But I'm not entirely sure, tbh. – davmac Nov 15 '16 at 08:57
  • 1
    @javaLover found it (C++14): [expr.new] _For arrays of char and unsigned char, the difference between the result of the new-expression and the address returned by the allocation function shall be an integral multiple of the strictest fundamental alignment requirement (3.11) of any object type whose size is no greater than the size of the array being created_. There is a lot of text in that section but I do believe the crux is that you can allocate a `char []` and it will be suitably aligned for storage of any type which has implicit alignment requirements. – davmac Nov 15 '16 at 09:27
  • Thank a lot. May you provide links or name of books which I should read (especially about alignment), please? I mean .... how did you know the answer? Some popular books like "A Tour of C++ 2014" doesn't mention about it. ...or did you just learn by doing? – javaLover Nov 15 '16 at 09:31
  • 1
    @javaLover the authoritative source is the standard document or drafts of it (which is where I found the quote above). See http://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents. However they are not particularly easy reading. If in doubt, ask a question here on StackOverflow :) – davmac Nov 15 '16 at 09:36