我有一个容器类:
class Container {
public:
MyItem* getItem() { return mItem.get(); }
private:
std::auto_ptr<MyItem> mItem;
};
我尝试编写initializeContainer()
方法,我使用Container.getItem()
来设置mItem
。以下是一些可能的方法,我在评论中对它们表示怀疑:
void initialize(Conatiner& container) {
MyItem item;
container.getItem() = &item; // Wrong, item gets destroyed at the end of the function
container.getItem() = new MyItem();
// This approach is filling my needs so far, but that doesn't necessarily
// mean it's correct.
// In particular, I'm not sure this approach properly removes the original item.
// Here I try to use placement new to reuse the memory pointed to by container.getitem
if (container.getItem()) {
MyItem* pItem = container.getItem();
pItem->~MyItem();
pItem = new (pItem) MyItem();
} // but if the pointer is null, I don't have any memory to reassign!
}
是否有通过指针处理填充字段的惯用方法?我无法访问C ++ 11功能或Boost等外部库。我也不允许更改Container
。
答案 0 :(得分:2)
initializeContainer()
无法通过普通渠道设置Container::mItem
成员。并且您无法使用Container::getItem()
来提供该访问权限,因为它会返回MyItem*
所持有的mItem
指针,并且您无法从该指针到达mItem
。< / p>
您需要更改Container
以允许访问mItem
,方法是:
为Container
提供设置mItem
的公共方法,然后让initializeContainer()
调用该方法:
class Container {
private:
std::auto_ptr<MyItem> mItem;
public:
MyItem* getItem() { return mItem.get(); }
void setItem(const MyItem &item) { mItem.reset(new MyItem(item)); }
};
void initialize(Container& container) {
MyItem item;
container.setItem(item);
}
将initializeContainer()
声明为friend
Container
,以便它可以直接访问private
个成员:
class Container {
private:
std::auto_ptr<MyItem> mItem;
public:
MyItem* getItem() { return mItem.get(); }
friend void initialize(Container&);
};
void initialize(Container& container) {
container.mItem.reset(new MyItem);
}
完全删除initializeContainer()
并改为使用Container
公共初始化方法:
class Container {
private:
std::auto_ptr<MyItem> mItem;
public:
void init() { mItem.reset(new MyItem); }
MyItem* getItem() { return mItem.get(); }
};
Container c;
c.init();
是否有通过指针处理填充字段的惯用方法?
不是你试图这样做的方式,不。您正在尝试使用与Container
对象本身无关的指针。因此,您无法使用该指针访问Container
对象的成员,因为它不会指向Container
对象开始。
我也不允许更改Container的界面。
那么,你运气不好,因为你试图做的事情需要改变界面。除非你使用丑陋的指针黑客,例如:
class Container {
private:
std::auto_ptr<MyItem> mItem;
public:
MyItem* getItem() { return mItem.get(); }
};
void initialize(Container& container) {
unsigned char *p = reinterpret_cast<unsigned char*>(&container);
std::auto_ptr<MyItem> *ap = reinterpret_cast<std::auto_ptr<MyItem>*>(p + offsetof(Container, mItem));
ap->reset(new MyItem);
}
另一方面,如果您的意图不是要更改mItem
本身,而只是(重新)初始化MyItem
已经拥有的mItem
对象,那么可以使用getItem()
,但前提是事先创建了MyItem
对象:
void initialize(Container &container) {
MyItem *item = container.getItem();
if (item) *item = MyItem();
}
您可以通过不允许mItem
首先保存空指针来确保:
class Container {
private:
std::auto_ptr<MyItem> mItem;
public:
Container() : mItem(new MyItem) {}
Container(const Container &src) : mItem(new MyItem(src.getItem())) {}
Container& operator=(const Container &rhs) { mItem.reset(new MyItem(rhs.getItem())); return *this; }
MyItem& getItem() { return *mItem.get(); }
};
答案 1 :(得分:1)
以下意味着修改类Container
和非空指针。
,例如,使用普通指针(不是auto
),并按引用返回:
#include <iostream>
class MyItem{
private:
int a;
public:
~MyItem(){std::cout<<"My item destroyed!\n";}
MyItem(int _a):a(_a){};
int getValue(){return a;}
};
class Container {
public:
MyItem & getItem() { return *(mItem); }
private:
MyItem* mItem;
};
void initialize(Container& container) {
std::cout<<"New item\n";
MyItem* p2=new MyItem(25);
std::cout<<"Getting item\n";
MyItem &p1 = container.getItem();
std::cout<<"Copying\n";
p1=*p2; // should define your own operator = for complex MyItem type
delete p2;
std::cout<<"New item\n";
MyItem* p3=new MyItem(5);
std::cout<<"Copying\n";
p1=*p3;
delete p3;
}
int main()
{
Container c;
initialize(c);
std::cout<<c.getItem().getValue()<<std::endl;
return 0;
}
输出:
New item
Getting item
Copying
My item destroyed!
New item
Copying
My item destroyed!
5
使用指针代替引用(仅更改相关代码块):
...
MyItem* getItem() { return mItem; }
...
MyItem *p1 = container.getItem();
std::cout<<"Copying\n";
*p1=*p2;
... (the same with p3)
...
std::cout<<c.getItem()->getValue()<<std::endl;
以下答案使用C++11
。
您可以通过引用访问unique_ptr
,然后使用移动语义
更改智能指针指向的对象的值。
一个例子
#include <iostream>
#include <memory>
class MyItem{
private:
int a;
public:
~MyItem(){std::cout<<"My item destroyed!\n";}
MyItem(int _a):a(_a){};
int getValue(){return a;}
};
class Container {
public:
std::unique_ptr<MyItem> & getItem() { return mItem; }
private:
std::unique_ptr<MyItem> mItem;
};
void initialize(Container& container) {
std::unique_ptr<MyItem> p2(new MyItem(5));
std::unique_ptr<MyItem> &p1 = container.getItem();
std::cout<<"Copying\n";
p1 = std::move(p2);
std::unique_ptr<MyItem> p3(new MyItem(20));
std::cout<<"Copying\n";
p1 = std::move(p3);
}
int main()
{
Container c;
initialize(c);
std::cout<<c.getItem()->getValue()<<std::endl;
return 0;
}