mardi 6 janvier 2015

How to return an object with no copy constructor

My questions concerns how to return an object that does not have a copy constructor. As an example let's imagine that I have some bigResource that sits in the heap, and let's say I keep track of it using a unique_ptr. Now suppose I give ownership of this resource to a caterpillar. Then I have a CaterpillarWithBigResource. Now at some point, this CaterpillarWithBigResource is going to turn into a ButterflyWithBigResource, so the Caterpillar object will have to transfer ownership to the Butterfly object.


I have written the following code to model the situation:



#include <cstdlib>
#include <iostream>
#include <memory>

class ButterflyWithBigResource {
public:

// If I uncomment just this line, I get an error
// ButterflyWithBigResource(const ButterflyWithBigResource& other) = default;

// If I uncomment just this line, I get an error
// ButterflyWithBigResource(const ButterflyWithBigResource& other) = delete;

// With both above lines commented out, I get no errors, and the program runs fine.

ButterflyWithBigResource(std::unique_ptr<int>&& bigResource) :
bigResource(std::move(bigResource)) {

}

const int& getResource() {
return *bigResource;
}

private:
std::unique_ptr<int> bigResource;
};

class CaterpillarWithBigResource {
public:

CaterpillarWithBigResource(int bigResource) :
bigResource(new int(bigResource)) {

}

ButterflyWithBigResource toButterfly() && {
return ButterflyWithBigResource(std::move(bigResource));
}
private:
std::unique_ptr<int> bigResource;
};

/*
*
*/
int main(int argc, char** argv) {
CaterpillarWithBigResource caterpillarWithBigResource(5);
ButterflyWithBigResource butterflyWithBigResource(std::move(caterpillarWithBigResource).toButterfly());
std::cout << butterflyWithBigResource.getResource() << std::endl;
return 0;
}


Notice that neither the Caterpillar nor the Butterfly have default copy constructors, because they each have a unique_ptr. However, I wouldn't expect this to be problem, so only move constructors should necessary. After all, I am only transferring ownership from the Caterpillar to the Butterfly.


In fact when I compile the program with g++ -c -g -std=c++11 -MMD -MP -MF using g++ version 4.8.2 it works just fine.


But now the weird thing is if I remind the compiler that the Butterfly's copy constructor is deleted by adding the line ButterflyWithBigResource(const ButterflyWithBigResource& other) = delete;, the program no longer compiles, and the compiler complains that copy constructor is deleted, so that I can't return the Butterfly in the toButterfly method.


If I then try to tell it that everything is ok by instead having the line ButterflyWithBigResource(const ButterflyWithBigResource& other) = default;, I again get the same error.


What I want to happen is for the Butterfly constructed in the toButterfly method to be moved to toButterfly's return address, and then later used as the argument of Butterfly's move constructor when constructing butterflyWithBigResource in main(). Is there a way to make this happen?


Aucun commentaire:

Enregistrer un commentaire