2016-07-07 109 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; 
}