CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 15
  1. #1
    Join Date
    Apr 2013
    Posts
    33

    Cloning an object

    Is there a point in dynamically creating a pointer during runtime only to dereference it? (if that is the right term, as in *pointer, depoint it?)
    In this case should I perhaps store pointers instead of references?

    Inventory.cpp


    Code:
    bool Inventory::addItem(InventoryItem& item)
    {
    	addItemAmount(item);
    
    	if (item.getAmount() > 0) {
    		if (hasEmptySlot()) {
    			addNewItem(*item.clone());
    			return true;
    		}
    		else return false;
    	}
    
    	return true;
    }
    
    void Inventory::addNewItem(InventoryItem& item)
    {
    	array.push_back(item);
    }
    InventoryItem.cpp

    Code:
    std::unique_ptr<InventoryItem> InventoryItem::clone(void) const
    {
    	return std::unique_ptr<InventoryItem>(new InventoryItem(index, name, type, maxAmount));
    }
    Also I was wondering, is there some sort of built-in cloning functionality or do I have to write the clone functions myself? When creating new instances I see that I can either pass the constructor properties or a reference to an object of the same type.

    For instance:

    Code:
    new InventoryItem(index, name....);
    new InventoryItem(const InventoryItem&);
    Is the second one casting?
    Last edited by royibernthal; April 8th, 2013 at 07:08 AM.

  2. #2
    Join Date
    Jan 2009
    Posts
    1,689

    Re: Cloning an object

    There sure is, but it's not pretty.

    Code:
    foobar * myobject = new foobar();
    foobar * clone = new foobar();  //allocate the space for it, don't use malloc
    memcpy(clone, myobject, sizeof(foobar));
    You are now 100% assured that clone is exactly the same as myobject.


    This is the preferred way to do it though.
    Code:
    foobar * myobject = new foobar();
    foobar * clone = new foobar(&myobject);
    The default copy constructor will copy what's in the object exactly, however, you can override it to change it's behavior so you aren't 100% guaranteed that it will be bit for bit the same. This is your second example, so no, it's not changing the type, it's copying it.

  3. #3
    Join Date
    Apr 2013
    Posts
    33

    Re: Cloning an object

    Okay I understand. Thanks.

  4. #4
    Join Date
    May 2009
    Posts
    2,413

    Re: Cloning an object

    Quote Originally Posted by royibernthal View Post
    Is there a point in dynamically creating a pointer during runtime only to dereference it?
    Usually there's no need to create transient value objects on the heap (unless they're very big and would cause the stack to overflow). This task is performed much better and faster by the stack. In fact I would be surprised if an aggressive optimizing compiler wouldn't try to sidestep your heap allocation altogether.

    In this case should I perhaps store pointers instead of references?
    You're not storing references in array (you cannot store references anywhere because they don't occupy space). You're storing copies of InventoryItem objects.

    Is the second one casting?
    No that's the call signature of the copy constructor of InventoryItem. The very same that's creating the copies I mentioned above.

    ---

    Once you've decided on value semantics for a class there are a couple of things to keep in mind.

    First, you must deal with the copy constructor and the assignment operator. In principle if a byte-by-byte copying of the class is fine you can use the default versions of these. Otherwise, if copying is more involved you need to supply your own. The sole job of the copy constructor and the assignment operator is to make sure a value object is properly copied. This means an explicit clone method seldom is necessary (although that approach sometimes is preferred).

    Second, since copying is involved, InventoryItem cannot be used polymorphically. If you did you would see strange things happening to your objects due to the so called slicing problem.

    Third, value semantics is preferred traditionally in C++. I guess mostly because the heap used to be slow and then in addition the nuisance of keeping track of who's responsible for deleting an object. But in my experience that has changed and today the heap is very fast. And smart pointers have become part of the C++ standard greatly simplifying heap object management. So I'd say value semantics is fine but only for small simple primitives-like classes. For higher abstractions smart pointers and the heap is a much better alternative. Especially if you come from an OO language with automatic memory management.
    Last edited by nuzzle; April 8th, 2013 at 10:45 AM.

  5. #5
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Cloning an object

    Quote Originally Posted by ninja9578 View Post
    There sure is, but it's not pretty.

    Code:
    foobar * myobject = new foobar();
    foobar * clone = new foobar();  //allocate the space for it, don't use malloc
    memcpy(clone, myobject, sizeof(foobar));
    You are now 100% assured that clone is exactly the same as myobject.
    The above is not guaranteed to give you a valid clone object. If all the members in foobar() are trivial then yes. If any of them have constructors or destructors, the above could be an application crash (or worse) waiting to happen.

    Note that in the case that the above would be safe, the compiler is capable of automagically creating a copy constructor for you. making your 2nd approach possible even without explicitely writing it. If the compiler can't make the copy constructor (and you don't want to), the above code is "a really bad idea".

  6. #6
    Join Date
    Apr 2013
    Posts
    33

    Re: Cloning an object

    nuzzle

    True, let me rephrase: In this case should I store pointers to the objects rather than the actual objects?

    Copying - Will having a clone function that creates a new instance with the same properties solve the polymorphism problem? (I can't think of a reason why not)

    Can you please explain what exactly value semantics are?

    OReubens

    Is the second way safer then?

    Code:
    foobar * myobject = new foobar();
    foobar * clone = new foobar(&myobject);

  7. #7
    Join Date
    May 2009
    Posts
    2,413

    Re: Cloning an object

    Quote Originally Posted by royibernthal View Post
    Can you please explain what exactly value semantics are?
    When performing operations on an object it must be clear whether we're concerned with what it holds (value semantics) or where it's at (reference semantics).

    It's a profound difference. For example if you compare two objects using value semantics you establish whether they're equal (contain the same), but if you use reference semantics you establish whether they're identical (are the same). If you pass an object to a function with value semantics you pass a copy, but if you pass it with reference semantics you pass information about its location.

    Different languages have different takes on the value/reference distinction and support it in different ways. Sometimes the distinction is upheld by the language, sometimes by the programmer, and often both. You sometimes do it for efficiency reasons and sometimes for design purposes.

    In Java it's simple, there's just one way. Primitives and references have value semantics and objects have reference semantics. In C++ it's more complex. You can mix and match pretty much as you like.

    Copying - Will having a clone function that creates a new instance with the same properties solve the polymorphism problem? (I can't think of a reason why not)
    Temporarily yes. But as soon as you make a copy you're toast. For example if you accidentally forget the & in a function call. Or if you store an object in an STL container (your array data structure is an std::vector right so there you go).

    True, let me rephrase: In this case should I store pointers to the objects rather than the actual objects?
    I suggest you store smart pointers. Just to show how simple and straightforward this approach is I've made a small example.

    Code:
    // InventoryItem
    
    typedef std::shared_ptr<class InventoryItem> InventoryItem_PTR; // smart pointer
    
    class InventoryItem { // interface
    public:
    	virtual ~InventoryItem(){}
    	virtual InventoryItem_PTR clone() const =0;
    	virtual void print() const =0;
    };
    
    class InventoryItem_Impl1 : public InventoryItem { // implementation
    public:
    	InventoryItem_Impl1(int i, const std::string& n) : index(i), name(n) {} 
    private:
    	virtual InventoryItem_PTR clone() const {
    		return InventoryItem_PTR(new InventoryItem_Impl1(index, name + " (clone)"));
    	}
    	virtual void print() const {
    		std::cout << index << "/" << name << std::endl;
    	}
    	int index;
    	std::string name;
    };
    
    // Inventory
    
    typedef std::shared_ptr<class Inventory> Inventory_PTR; // smart pointer
    
    class Inventory { // interface
    public:
    	virtual ~Inventory(){}
    	virtual bool addItem(const InventoryItem_PTR& item) =0;
    	virtual void print() const =0;
    };
    
    class Inventory_Impl1 : public Inventory { // implementation
    private:
    	virtual bool addItem(const InventoryItem_PTR& item) {
    		if (true) {
    			addNewItem(item);
    			addNewItem(item->clone());
    			return true;
    		}
    		return false;
    	}
    	virtual void print() const {
    		for (const InventoryItem_PTR& item : array) {
    			item->print();
    		}
    	}
    	void addNewItem(const InventoryItem_PTR& item)	{
    		array.push_back(item);
    	}
    	std::vector<InventoryItem_PTR> array;
    };
    
    // testing
    
    void test() {
    	Inventory_PTR inventory = Inventory_PTR(new Inventory_Impl1());
    	InventoryItem_PTR item = InventoryItem_PTR(new InventoryItem_Impl1(1,"One")); 
    	inventory->addItem(item);
    	inventory->addItem(InventoryItem_PTR(new InventoryItem_Impl1(2,"Two")));
    	inventory->print();
    }
    Last edited by nuzzle; April 9th, 2013 at 11:11 PM.

  8. #8
    Join Date
    Apr 2013
    Posts
    33

    Re: Cloning an object

    Thanks you for the great reply

    I'm pretty certain we're on the same page on cloning but just in case, I might have explained myself poorly.
    By creating my own clone function I mean creating a new instance via the constructor like in the code in your last reply.
    Is polymorphism still a problem? Is so, sorry for being slow, but I can't really understand why. If we're on the same page then in a couple of OOP languages I used for instance it wasn't a problem.

    Is there reason why you used shared pointers? For InventoryItem do they count how many different InventoryItem instances there are or pointers pointing to the same instance? (if that's possible, I'm not familiar at all with shared pointers and unsure about their purpose)

  9. #9
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Cloning an object

    Quote Originally Posted by royibernthal View Post
    Is the second way safer then?

    Code:
    foobar * myobject = new foobar();
    foobar * clone = new foobar(&myobject);
    It's safe
    However. Whether or not the variable 'clone' actually qualifies as a clone is open for discussion, it depends what your definition of a clone is.

    The above doesn't "make clones". It constructs new foobar's based on an existing foobar isntance. the copy constructor could do very weird things that wouldn't qualify as "clone", there are no guarantees that a copy constructor actually makes "copies". There are "common expectations" on what a copy constructor should do especially if you intend to use those objects in STL containers or other libraries, but implementation is another matter.

  10. #10
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Cloning an object

    If I may, I'll just add this to the value vs reference semantics: when it comes to comparison, think of value semantics as of money - with money, if you're an ordinary person, you don't really care if you get this 100$ bill or that 100$ bill - they are all the same to you. For your purposes, they don't have identity, what's relevant about them is their value.

    On the other hand, references are things that refer to (or point to, regardless of what that means implementation-wise) some other object. For example, phone numbers are references to someone's phone. The referred-to objects normally do have identity. You might have two phone numbers that reference two phones that are technically exactly the same (equal by value), but you normally do care very much which phone you want to call, if you want to contact the right person. (Here I assume that the ownership of the phone is not a part of the phone object's state - a model which might correspond with what you may find in an actual program).

  11. #11
    Join Date
    Apr 2013
    Posts
    33

    Re: Cloning an object

    You sound like my old teacher complicating stuff with stories
    Apparently I'm already familiar with all of that, I just wasn't aware it was called "value/reference semantics".

    OReubens - Okay I understand, all in all it sounds like creating my own clone function would be the best approach, that way I can know for sure what I end up with.

  12. #12
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Cloning an object

    Quote Originally Posted by royibernthal View Post
    You sound like my old teacher complicating stuff with stories
    Apparently I'm already familiar with all of that, I just wasn't aware it was called "value/reference semantics".
    LOL. OK, then, sorry. Different people learn in different ways, maybe analogies aren't your thing. But, no problem, since you already understand the concept.

  13. #13
    Join Date
    Apr 2013
    Posts
    33

    Re: Cloning an object

    I seldom resort to analogies, I prefer to keep things simple. Thanks though
    Last edited by royibernthal; April 11th, 2013 at 01:27 PM.

  14. #14
    Join Date
    May 2009
    Posts
    2,413

    Re: Cloning an object

    Quote Originally Posted by royibernthal View Post
    I'm pretty certain we're on the same page on cloning but just in case,
    Slicing only happens when an object is upcasted by value (is copied upwards in its inheritance hierarchy), like

    Code:
    class Base {};
    class Derived : public Base {};
    //
    Derived d;
    Base b = d; // slicing
    Derived clone = d; // no slicing
    Since cloning means creating an identical copy (same value, same class) of an object it is safe, both when performed by the copy constructor or assignment operator as well as with some other constructor or method to the same effect.

    Is there reason why you used shared pointers?
    There is for sure. Shared pointers greatly facilitate the OO programming style in C++ by removing (or at least easing) some major hurdles including problems associated with,

    - value semantics and polymorphism (slicing), and
    - pointer ownership (memory leaks, stale and dangling pointers).

    Shared pointers are garbage collection light if you will. The only fundamental drawback is that they cannot handle cyclic pointing. Even the sun has spots .
    Last edited by nuzzle; April 12th, 2013 at 02:19 AM.

  15. #15
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Cloning an object

    Quote Originally Posted by TheGreatCthulhu View Post
    If I may, I'll just add this to the value vs reference semantics: when it comes to comparison, think of value semantics as of money - with money, if you're an ordinary person, you don't really care if you get this 100$ bill or that 100$ bill - they are all the same to you. For your purposes, they don't have identity, what's relevant about them is their value.
    heh


    Hi mr. electronics salesman.. I would like to purchase that there huge HD flatpanel TV screen. Yes, I will pay you with a reference to some nice crisp 100$ bills that I have lying in my safe at home. ;-)


    One can dream...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured