防止temporary延长其生命周期
Prevent temporary from extending its lifetime?
这可能是不可能的,但我想知道是否有可能使临时对象永远不会超过其原始表达式。我有一个指向父对象的对象链,和一个创建子对象的成员函数,这里有一个简化的例子
class person{
string name;
person * mommy;
public:
person(const string & nam, person * m = 0) : name(nam), mommy(m) {}
person baby(const string & nam){
return person(nam, this);
}
void talk() const{
if (mommy) mommy->talk();
cout << name << endl;
}
};
int main(){
person("Ann").baby("Susan").baby("Wendy").talk(); // fine
const person & babygirl = person("Julie").baby("Laura"); // not fine
babygirl.talk(); // segfault
return 0;
}
我想使用person
的方式是将其传递给一个函数,就像这样:
void use(const person & p) {
p.talk();
}
use(person("Anna").baby("Lisa"));
很好。
只要没有一个临时变量存在于原始表达式之后,这将很好地工作,但是如果我将一个最后的临时变量绑定到const引用,它的父变量将不存在,并且我得到一个段错误。我可以隐藏person
的复制构造函数和赋值操作符,但是有什么方法可以防止这种错误的发生吗?如果可能的话,我希望避免动态分配。
看起来您正在创建一个数据结构,其中子节点有指向父节点的指针。在这种情况下,使用临时对象肯定会给您带来痛苦。为了使其安全,您需要动态分配并可能使用某种引用计数。
您考虑过使用boost::shared_ptr
吗?它是一个引用计数智能指针类的实现。使用shared_ptr
和一些工厂方法,您可能能够获得您想要的效果,并减少动态内存分配的痛苦。我试了一下,似乎很有效。一旦代码退出作用域,对象就全部销毁,因为没有对shared_ptrs的引用了。
为了响应zounds的注释,我修改了示例,以便根对象控制数据结构的生命周期。
#include <iostream>
#include <string>
#include <vector>
#include <boostshared_ptr.hpp>
#include <boostweak_ptr.hpp>
using boost::shared_ptr;
using boost::weak_ptr;
using std::string;
using std::cout;
using std::endl;
using std::vector;
class person;
typedef shared_ptr<person> Person;
typedef weak_ptr<person> PersonWk;
class person {
PersonWk pThis;
friend Person makePerson(const string & nam, Person m = Person());
string name;
PersonWk mommy; // children should not affect parent lifetime, so store weak ptr
vector<Person> children; // parents affect children lifetime so store child shared ptrs
// make constructor private so that you can only make a person using factory method
person(const string & nam, Person m) : name(nam), mommy(m)
{
// for demo purposes
printf("creating %sn", nam.c_str());
++personCount;
}
// undefined copy constructor and assignment operators
person(const person&);
person& operator=(const person&);
public:
// for demo purposes
static int personCount;
~person()
{
// for demo purposes
printf("destroying %sn", name.c_str());
--personCount;
}
Person baby(const string & nam){
Person child = makePerson(nam, Person(pThis));
children.push_back(child);
return child;
}
void talk() const{
if (Person mom = mommy.lock())
mom->talk();
cout << name << endl;
}
};
int person::personCount = 0;
// factory method to make a person
Person makePerson(const string & name, Person m) {
Person p = Person(new person(name, m));
p->pThis = p; // stash weak_ptr so I can use it to make a shared_ptr from "this" in the baby method
return p;
}
void use(const Person p) {
printf("In method use...n");
p->talk();
}
int _tmain(int argc, _TCHAR* argv[])
{
printf("personCount=%dn", person::personCount);
{
Person ann = makePerson("Ann");
// ann has baby and grandbaby, pass grandbaby to use method
use(ann->baby("Susan")->baby("Wendy"));
ann.reset(); // remove reference from root object. Destruction ensues...
}
printf("personCount=%dn", person::personCount);
return 0;
}
你必须这样做:
void use(const person & p) {
p.talk();
}
person a("Anna");
use(a.baby("Lisa"));
这样,父类"a"就不会超出作用域,直到你真正使用它(在调用"use"之后)。
原始代码的问题是父类"Anna"只需要在调用"baby"之前停留足够长的时间,并且可以在进行函数调用之前丢弃父类。通过使父变量成为一个有作用域的变量,你可以控制何时销毁它。
这看起来危险吗?是的。因此,我建议看看m-sharp对动态分配的回答。但是如果你想要一个不需要引用计数等的方法,那么你可以这样做…
- 如何在共享库的整个生命周期内存储数据
- 如何理解句子的生命周期始于对e的评估
- 它解决了什么问题,对于非真空初始化,生命周期在初始化之前就开始了
- Go/C++gRPC客户端通道和存根生命周期
- 如何将"this"的生命周期移动到C++中的另一个对象中?
- 是否可以通过使用移动/交换 c++11 来延长返回的临时变量的生命周期
- 使用对象的生命周期作为设置器的安全性
- 临时人员的生命周期传递给函数
- 我想知道在构造函数中初始化变量时的生命周期
- Lua 用户数据生命周期管理
- 如何使用 epoll(void* event.data.ptr) 管理 Connection 的生命周期
- C++引用的生命周期
- 在堆栈上有一个对象,而不是在函数的整个生命周期内
- 在 Boost ASIO 服务器中处理生命周期
- C++ lambda 生命周期
- 使用互斥锁跟踪另一个应用的生命周期
- QSharedPointer 或 std::shared_ptr 的生命周期
- 来自async_resolve的 boost::asio::ip::tcp::resolver::iterator 的生命周期是多久?
- 如何调整属于类的唯一指针的字符数组的大小.它必须在程序的整个生命周期中保持活力
- 延长 std::tuple<int&,int> 的生命周期,方法是将其分配给 const std::tuple<int, int>&