Reputation: 1226
My project uses custom allocator that constructs objects the following way:
template <typename T, typename... Args>
T* create(Args... args)
{
T* object = // request "bare" memory
// call object constructor
return new(reinterpret_cast<void*>(object)) T(args...);
}
There is a class, containing const reference as a field:
struct A {
A(const string& s) : str_(s) {
cout << &s << '\n';
}
const string& str_;
};
But when I'm trying to create an object, I'm getting wrong results:
string* str = new string("some string");
cout << str << '\n';
A* a = create<A>(*str);
The output:
0x7fffc8004db4
0x7fffd5436050
I thought the const reference field (str_
) should contain the same address, that has been given to construction machinery, but obviously it isn't true.
Why is it happen, and how to avoid it?
Ofc, I can not help using custom allocators, it is mandatory, I wouldn't ask.
Upvotes: 4
Views: 3901
Reputation: 206607
The call
A* a = create<A>(*str);
creates a copy of *str
and uses the copy to call the function since the function is declared as
template <typename T, typename... Args>
T* create(Args... args) {...}
a
has a reference to an object that is no longer alive.
Use
template <typename T, typename... Args>
T* create(Args&&... args)
{
T* object = // request "bare" memory
// call object constructor
return new(reinterpret_cast<void*>(object)) T(std::forward<Args>(args)...));
}
instead.
Upvotes: 2
Reputation: 21576
template <typename T, typename... Args>
T* create(Args... args)
{
T* object = // request "bare" memory
// call object constructor
return new(reinterpret_cast<void*>(object)) T(args...);
}
All your variadic arguments will be passed by value. Hence a copy is being made. You probably want to use forwarding references:
template <typename T, typename... Args>
T* create(Args&&... args)
{
auto memory = // request "bare" memory
// call object constructor
return new(memory) T(std::forward<Args>(args)...);
}
Prints:
0x111ac20 0x111ac20
Again consider data alignment whenever you want to use placement-new.
Upvotes: 4