一个例子:
class A
{
....
A func();
};
A A::func()
{
...
return something;
}
在汇编级别,编译时,函数A::func
实际上有两个参数:第一个是this
指针,第二个是临时A
的地址对象,由调用者创建以存储返回值。
例如,如果我们编写a.func()
,程序将在堆栈中创建一个临时A
对象(让我们称之为t
),并传递a
的地址作为第一个参数,t
的地址作为第二个参数,最后调用函数func
。
以下是我的问题:在A::func
的实现中,我们可以获得a
的地址 - 它是指针this
;但是我们有办法获得t
的地址吗?它叫什么名字?
如果我想在返回结果之前做一些内存alloc / free,那么它是有用的。
以下是我想要做的一个例子:
class A
{
int * data;
A func();
};
A A::func()
{
// here "ret_p" is the pointer to the return value (let's pretend that it exists)
ret_p->data = new int[some length];
...
return * ret_p;
}
当然,我可以在A::func
中创建一个本地对象然后返回它;但是程序将在我的本地对象和调用者创建的临时对象之间进行复制。由于调用者已经创建了一个临时对象,我希望通过直接使用它来节省时间和空间。那可能吗?
嗯,这可能是出于c ++,但我仍然希望......
答案 0 :(得分:1)
堆栈中没有这样的临时A
对象参数(t
)。
如果您在里面调用A a1 = a.func();
和return something;
,则会调用copy constructor
,相当于此A a1(something);
。 a1
和something
是不同的实例。
如果您在A a1; a1 = a.func();
和return something;
内,则会调用a1 = something; // (operator =)
。 a1
和something
是不同的实例。
如果你在里面拨打A a1 = a.func();
和return A(p1);
,这相当于A a1(p1);
,有一个实例a1
。
如果您直接致电a.func();
而未分配内部的var和return something;
,则返回时不会发生任何事情。
如果直接调用a.func();
而未分配内部的var和return A(p1);
,则会构造一个临时对象,然后立即销毁。
如果你在A a1; a1 = a.func();
和return A(p1);
里面,将构造一个临时对象,然后将调用operator = a1 = temp object;
,然后销毁临时对象。
供您参考。
毕竟,A a1 = a.func()
或A a1; a1 = a.func()
,return something; // a var
或return A(p1); // call constructor
会导致不同的行为,我认为您可以正确控制记忆。
答案 1 :(得分:0)
向&a
提供func
是copy elision的一种形式。
无法保证会发生任何事情,并且无法对C ++级别的实施进行访问。
当你说“我想在返回结果之前做一些内存分配/免费”时,我不认为你自己清楚了,你能给出一个具体的例子吗?可能你需要的一切都是通过复制省略,移动运算符和RAII来实现的。
回应你的例子,这是你应该怎么做的。
class A
{
std :: vector <int> data;
A func();
};
A A::func()
{
A ret;
ret .data .assign (some_length, 123); // or whatever;
return ret;
}
由于copy elision,可能会自动优化你想要的方式。如果您认为编译器不会删除副本,请添加移动构造函数。
A :: A (A && old)
: data (std :: move (old .data))
{
}
std::vector
的移动构造函数将简单地复制指针。如果你想知道 的工作方式,那么这里就是本土的等价物。
class A
{
int * data;
// Allocate
A (size_t size) : data (new int [size]) {}
// Free, only if we haven't moved.
~ A () {if (data) delete [] data;}
// Move
A (A && old) : data (old .data) {old .data = nullptr;}
A (const A &) = delete; // or implement with a new allocation.
}