Reputation: 94225
Can I call constructor explicitly, without using new
, if I already have a memory for object?
class Object1{
char *str;
public:
Object1(char*str1){
str=strdup(str1);
puts("ctor");
puts(str);
}
~Object1(){
puts("dtor");
puts(str);
free(str);
}
};
Object1 ooo[2] = {
Object1("I'm the first object"), Object1("I'm the 2nd")
};
do_smth_useful(ooo);
ooo[0].~Object1(); // call destructor
ooo[0].Object1("I'm the 3rd object in place of first"); // ???? - reuse memory
Upvotes: 63
Views: 38804
Reputation: 152
The problem is that normally you need an already existing object on which to call the functions (unless it is a static function), so for the constructor that's a bit of a an issue when you want to do it in a nonstandard way.
Here's how to create a new class object in existing memory without using new
. This will even work with raw memory from malloc()
, provided you first memset()
the memory to zeros.
#include <string>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <vector>
class Str_obj{
public:
char* str;
constexpr Str_obj(const Str_obj& obj) = default;
Str_obj(const char* str1){
str = strdup(str1);
puts("ctor");
puts(str);
}
~Str_obj(){
puts("dtor");
puts(str);
free(str);
str = nullptr;
}
Str_obj& operator = (const Str_obj& obj){
puts("copy assign");
free(str);
str = strdup(obj.str);
return *this;
}
Str_obj& operator = (Str_obj&& obj){
puts("move assign");
free(str);
str = obj.str;
obj.str = nullptr;
return *this;
}
};
std::vector<std::string>
to_string_vec(Str_obj* arr, size_t len){
std::vector<std::string> str_arr(len);
for(int i = 0; i < len; ++i){
str_arr[i] = std::string(arr[i].str);
}
return str_arr;
}
int main() {
std::cout<<"Creating objects:\n";
constexpr size_t len = 2;
Str_obj arr[len] = {
Str_obj("I'm the first object"),
Str_obj("I'm the 2nd")
};
std::vector<std::string> str_arr1 = to_string_vec(arr, len);
std::cout<<"\n";
std::cout<<"Destruct and replace object:\n";
arr[0].~Str_obj(); // call destructor
// Calls constructor, then move assign to existing memory.
arr[0] = std::move(Str_obj("I'm the 3rd object in place of first"));
std::vector<std::string> str_arr2 = to_string_vec(arr, len);
std::cout<<"\n";
for(int i = 0; i < len; ++i){
std::cout<<i<<". "<<str_arr1[i]<<"\n";
}
std::cout<<"\n";
for(int i = 0; i < len; ++i){
std::cout<<i<<". "<<str_arr2[i]<<"\n";
}
return 0;
}
Possible output:
Creating objects:
ctor
I'm the first object
ctor
I'm the 2nd
Destruct and replace object:
dtor
I'm the first object
ctor
I'm the 3rd object in place of first
move assign
dtor
0. I'm the first object
1. I'm the 2nd
0. I'm the 3rd object in place of first
1. I'm the 2nd
dtor
I'm the 2nd
dtor
I'm the 3rd object in place of first
Upvotes: 0
Reputation: 1
You can use the following template
template <typename T, typename... Args>
inline void InitClass(T &t, Args... args)
{
t.~T();
new (&t) T(args...);
}
usage:
struct A
{
A() {}
A(int i) : a(i) {}
int a;
} my_value;
InitClass(my_value);
InitClass(my_value, 5);
Upvotes: 0
Reputation: 4893
Based on comments, this only works for Microsoft C++ compilers
Quite simply, without new
:
imguistate = (int *)malloc(ImGui::GetInternalStateSize());
memset(imguistate, 0, ImGui::GetInternalStateSize());
((ImGuiState *)imguistate)->ImGuiState::ImGuiState();
This works with any class:
class SomeClass {
public:
SomeClass() {
printf("Called constructor\n");
}
};
int main () {
SomeClass *someclass = new SomeClass;
someclass->SomeClass::SomeClass(); // call constructor again
}
Upvotes: -3
Reputation: 399803
Sort of. You can use placement new to run the constructor using already-allocated memory:
#include <new>
Object1 ooo[2] = {Object1("I'm the first object"), Object1("I'm the 2nd")};
do_smth_useful(ooo);
ooo[0].~Object1(); // call destructor
new (&ooo[0]) Object1("I'm the 3rd object in place of first");
So, you're still using the new
keyword, but no memory allocation takes place.
Upvotes: 88
Reputation: 8907
Let me show you some code on how it can be done, both in construction and destruction
#include <new>
// Let's create some memory where we will construct the object.
MyObject* obj = (MyObject*)malloc(sizeof(MyObject));
// Let's construct the object using the placement new
new(obj) MyObject();
// Let's destruct it now
obj->~MyObject();
// Let's release the memory we used before
free(obj);
obj = 0;
I hope the above summary makes things clearer.
Upvotes: 20
Reputation: 283634
Literally speaking, NO, you can't do it without the "new" keyword. See all the answers about placement new for the way to use the "new" keyword to call the constructor without actually allocating memory.
Upvotes: 6
Reputation: 96109
Yes, using placement new - as above, but you might consider having a second factory class to manage the storage, even if it means copying an object. memcpy() is generally cheap for small objects.
Upvotes: 1
Reputation: 35188
I think you're looking for Placement New. The C++ FAQ Lite has a good summary of how you do this. There are a few important gotchas from this entry:
#include <new>
to use the placement new syntax.Upvotes: 17
Reputation: 31406
Yes, when you've got your own allocated buffer you use placement new. Brian Bondy has a good response here in a related question:
What uses are there for "placement new"?
Upvotes: 2
Reputation: 44578
You can call a destructor, but memory will not be reclaimed, and your call will be equivalent to a function call. You have to remember that underneath the destructor does 2 things: destructs object based on your specification, and reclaims the memory. Since you dtor will be called anyway for an object allocated on the stack, calling it twice may result in an undefined behavior.
Upvotes: 1