2016-07-07 105 views
0

我有一个容器类填写私有字段。下面是一些可能的方法,我对他们的评论质疑:通过返回指针

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的界面。

+3

请停止使用'的std :: auto_ptr',在某些情况下,它可能是危险的,它已被从C++ 11赞成['性病弃用:: unique_ptr'](http://en.cppreference.com/w/cpp/memory/unique_ptr),而'std :: auto_ptr'将从C++ 17标准中删除。 –

+1

如果你只是想通过公共功能进行修改,为什么要保持私密?无论如何,'* container.getItem()= MyItem();'? –

+2

还要注意'getItem'通过值返回存储的指针*,所以在左边执行任何赋值'getItem'的操作都不起作用。可能做例如'* container.getItem()= MyItem()'应该可以工作。它*不会绕过智能指针的整个“所有权”模型。 –

回答

2

initializeContainer()根本不具有访问通过正常渠道来设置Container::mItem构件。并且您不能使用Container::getItem()来提供该访问权限,因为它返回指向mItem的​​指针,并且您无法从该指针到达mItem

您需要更改Container允许访问mItem,无论是通过:

  1. 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); 
    } 
    
  2. 声明initializeContainer()作为friendContainer所以它可以直接访问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); 
    } 
    
  3. 摆脱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本身,而是简单地(重新)初始化MyItem对象mItem已经拿着,你可以使用getItem()这一点,但只有当MyItem对象事先已创建:

void initialize(Container &container) { 
    MyItem *item = container.getItem(); 
    if (item) *item = MyItem(); 
} 

您可以通过不允许012保证持有空指针摆在首位:

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

以下意味着修改了类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; 
}