我正在开发一些课程并且遇到了这个问题。 考虑我有以下课程:
struct A
{
int *p;
A()
{
p = new int(1);
cout << "ctor A" << endl;
}
A(const A& o)
{
cout << "copy A" << endl;
p = new int(*(o.p));
}
A(A&& o)
{
cout << "move A" << endl;
p = std::move(o.p);
o.p = NULL;
}
A& operator=(const A& other)
{
if (p != NULL)
{
delete p;
}
p = new int(*other.p);
cout << "copy= A" << endl;
return *this;
}
A& operator=(A&& other)
{
p = std::move(other.p);
other.p = NULL;
cout << "move= A" << endl;
return *this;
}
~A()
{
if(p!=NULL)
delete p;
p = NULL;
cout << "dtor A" << endl;
}
};
以下以A
作为属性的类:
class B {
public:
B(){}
A myList;
const A& getList() { return myList; };
};
这个函数检查一些变量值并在不同的情况下返回不同的对象:
B temp;
A foo(bool f)
{
A a;
*a.p = 125;
if (f)
return a;
else
{
return temp.getList();
}
}
现在,我想使用这个函数:
A list1 = foo(true);
if(list1.p != NULL)
cout << (*list1.p) << endl;
cout << "------"<<endl;
A list2 = foo(false);
if (list2.p != NULL)
cout << (*list2.p) << endl;
这种情况的目的是:
如果参数为foo
,函数p
应该返回(或移动)而不复制true
中的更改的某个本地对象,或者应返回全局变量temp
的属性而不返回调用A
的复制构造函数(即返回myList
的引用)并且它不应该从myList
抓取B
(它不应该从{{myList
中删除B
1}},如果参数为std::move
,则无法使用false
。
我的问题是:
我应该如何更改功能foo
以遵循上限条件? foo
的当前实现在true
情况下正常工作并移动该局部变量,但如果false
它调用list2
的复制构造函数。其他想法是以某种方式延长局部变量的生命周期,但添加const引用对我来说不起作用。目前的输出是:
ctor A
ctor A
move A
dtor A
125
------
ctor A
copy A
dtor A
1
dtor A
dtor A
dtor A
答案 0 :(得分:3)
如果您可以将B
更改为
class B {
public:
B(){}
std::shared_ptr<A> myList = std::make_shared<A>();
const std::shared_ptr<A>& getList() const { return myList; };
};
然后foo
可以是:
B b;
std::shared_ptr<A> foo(bool cond)
{
if (cond) {
auto a = std::make_shared<A>();
*a->p = 125;
return a;
} else {
return b.getList();
}
}
输出
ctor A
ctor A
125
------
1
dtor A
dtor A
答案 1 :(得分:2)
最简单的解决方案可能就是在Jarod42的答案中使用std::shared_ptr
。但是如果你想避免使用智能指针,或者你不能改变B
,你可以创建自己的包装类,它可能拥有A
,也可能不拥有std::optional
。 class AHolder {
private:
std::optional<A> aValue;
const A& aRef;
public:
AHolder(const A& a) : aRef(a) {}
AHolder(A&& a) : aValue(std::move(a)), aRef(aValue.value()) {}
const A* operator->() const { return &aRef; }
};
可能非常方便:
optional
如果需要,该类包含A
拥有foo
,您可以使用move-semantics将其移入。该类还包含引用包含值的引用(或指针)或引用另一个对象。
您可以从AHolder foo(bool f)
{
A a;
*a.p = 125;
if (f)
return a;
else
{
return temp.getList();
}
}
:
auto list1 = foo(true);
if(list1->p != nullptr)
cout << (*list1->p) << endl;
cout << "------"<<endl;
auto list2 = foo(false);
if (list2->p != nullptr)
cout << *list2->p << endl;
调用者可以访问包含的引用:
std::optional
如果您无法访问boost::optional
std::unique_ptr
,或者您可以以动态内存分配为代价使用h = 1/20
g2 = matrix(NA, 5000, 1)
#notice na.rm = TRUE below which will remove NAs in the sum calculation
for (j in 1:5000) {
g2[j] = pexp(j + (1 / 2) * h,
rate = 1,
lower.tail = TRUE,
log.p = FALSE)
if (sum(g2, na.rm = TRUE) > 0.8) break
print(g2)
}
。
答案 2 :(得分:0)
您的函数 foo 返回 A 的实例,而不是引用(也不是指针),因此您无法访问 B.myList < / em>内容无需复制或移动。
为了获得此访问权限,您应该使用智能指针(如Jarod42写的)或只是这样的简单指针:
B temp;
A* foo(bool f)
{
if (f)
{
A* ptr = new A;
*ptr->p = 125;
return ptr;
}
else
{
return &temp.getList();
}
}
然而,这个特定的代码将不起作用coz .getList()返回const引用,但 foo 返回非const指针(这可能但不应该是使用const_cast&lt的黑客攻击;&GT)。
通常,您需要选择 foo 函数应该返回的内容:
如果你必须在运行时做出这个决定(例如你的bool参数)那么指针(简单或智能 - 无论如何)是唯一的选择(还记得删除手动分配的内存)。