2

我的项目使用构造对象通过以下方式自定义分配器:与常量引用可变参数模板

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...); 
} 

有一类,含常量引用作为一个字段:

struct A { 
    A(const string& s) : str_(s) { 
    cout << &s << '\n'; 
    } 

    const string& str_; 
}; 

但是,当我米试图创建一个对象,我得到错误的结果:

string* str = new string("some string"); 
cout << str << '\n'; 
A* a = create<A>(*str); 

输出:

0x7fffc8004db4 
0x7fffd5436050 

我以为const引用字段(str_)应该包含相同的地址,这已经给了施工机械,但显然这是不正确的。

为什么会发生,以及如何避免它?

Ofc,我不禁使用自定义分配器,这是强制性的,我不会问。

回答

2
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...); 
} 

所有的可变参数都会按值传递。因此正在制作副本。你可能想使用转发引用:

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)...); 
} 

打印:

0x111ac20 
0x111ac20 

Demo


再次考虑数据对齐,每当你想使用投放新

+0

我请你原谅,也许我错过了一些东西......还有其他的关于比对的condiderations,而不是分配一个sizeof(T)'大小的内存块吗? 'sizeof'不报告已经对齐的大小? – Alexey

2

呼叫

A* a = create<A>(*str); 

创建的*str副本,并使用副本,以调用函数,因为该函数被声明为

template <typename T, typename... Args> 
T* create(Args... args) {...} 

a具有一个对象,它不再是一个参考活。

使用

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)...)); 
} 

代替。

+2

不完美的转发比采用'const&'更好,然后将其复制到构造函数中? – Rakete1111

+3

@ Rakete1111,是的,它会的。由于我仍然在VS2008工作,使用完美的转发不会跳出作为我心中的第一件事:) :) –

相关问题