通过返回的指针填充私有字段
Fill private fields through returned pointers
我有一个容器类:
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
的界面。
initializeContainer()
根本无法通过正常渠道设置Container::mItem
成员。 而且不能使用 Container::getItem()
来提供该访问权限,因为它返回mItem
持有的MyItem*
指针,并且您无法从该指针访问mItem
。
您需要通过以下方式更改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()
声明为Container
的friend
,以便可以直接访问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
对象。
我也不允许更改容器的接口。
好吧,那么你就不走运了,因为你试图做的事情需要改变界面。 除非您使用丑陋的指针黑客,例如:
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
本身,而只是(重新)初始化mItem
已经持有的MyItem
对象,你可以使用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(); }
};
以下内容意味着对类 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 itemn";
MyItem* p2=new MyItem(25);
std::cout<<"Getting itemn";
MyItem &p1 = container.getItem();
std::cout<<"Copyingn";
p1=*p2; // should define your own operator = for complex MyItem type
delete p2;
std::cout<<"New itemn";
MyItem* p3=new MyItem(5);
std::cout<<"Copyingn";
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<<"Copyingn";
*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<<"Copyingn";
p1 = std::move(p2);
std::unique_ptr<MyItem> p3(new MyItem(20));
std::cout<<"Copyingn";
p1 = std::move(p3);
}
int main()
{
Container c;
initialize(c);
std::cout<<c.getItem()->getValue()<<std::endl;
return 0;
}
- 将结构字段的类型展开为可变模板参数
- 将位字段导出到数组
- 为了方便起见,我应该避免公开私有字段变量吗
- 当字段可以为null时,如何使用C++接口在Avro中写入数据
- sizeof 函数如何在带和不带位字段的结构上工作?(填充)
- 使用 cin >> 和 cout <<填充类C++的字段
- C 如何从UCHAR数组中填充结构的位字段
- 在 C++ 中填充重复的自定义协议缓冲区字段
- 使用out类型转换,我如何填充位字段
- 当您有结构名称和字段值的列表时,是否可以以编程方式创建结构的对象并填充字段
- C++结构填充和字段打包
- 如何查找和填充第三方源的 Flash 字段
- 有没有办法控制C++中结构成员(包括位字段)之间的填充
- ProtocolBuffer缺少必需的字段,但这些字段已填充
- 在Blackberry Cascades 10(C++、Qt、QML)中,如何在填充字段的情况下调用电子邮件客户端
- Gcc /clang在基结构的后填充中布局派生结构的字段
- 如何删除空字段(或填充了不正确的数据)
- 只有在填充了两个字段时才启用按钮
- 在循环中填充C++对象字段会导致空字段
- 通过返回的指针填充私有字段