efficiently passing and returning objects in c++ - c++

I have a Visual Studio 2008 C++ application where a function Foo::CreateBar uses an internal function to populate a buffer with some data as below. I understand that VS2008 will use return value optimization (RVO) to ensure the Foo::GetData() call will not incur a copy, but will I incur copies for the Bar constructor? How about for returning the Bar object from Foo::CreateBar Is there a more efficient way to do this? Do I need to redefine my Buffer as boost::shared_ptr< std::vector< BYTE > >?
typedef std::vector< BYTE > Buffer;
class Bar
{
public:
explicit Bar( Buffer buffer ) : buffer_( buffer ) { };
// ...
private:
Buffer buffer_;
};
class Foo
{
public:
Bar CreateBar() const { return Bar( GetData() ); };
// ...
private:
static Buffer GetData()
{
Buffer buffer;
// populate the buffer...
return buffer;
};
};
Thanks,
PaulH

You can answer this question for sure by examining the assembler code that's generated for this source - modify the compiler output options to produce a listing interlaced with the source code.
shared_ptr is not appropriate, in any case. That's a device for the programmer to manage designs requiring shared objects efficiently, not to fool the compiler into not constructing more objects than it should.

Using a const reference as parameter of the Bar constructor
explicit Bar( const Buffer & buffer ) : buffer_( buffer ) { };
will surely avoid you the copy caused by the pass-by-value in the constructor call, but you will have a copy in the construction of the buffer_ field.

shared_ptr would work. unique_ptr would work, because ownership is transferred.
You could also use out parameters to avoid the copy. Add a factory function...
class Bar
{
public:
explicit Bar( void (*factory)(Buffer& buffer) ) { factory(buffer_); }
// ...
private:
Buffer buffer_;
};
class Foo
{
public:
Bar CreateBar() const { return Bar( GetData ); }
// ...
private:
static void GetData(Buffer& buffer)
{
// populate the buffer...
}
};

You should make a couple of different tests and see what your compiler does with it. In the code above there are as many as 4 copies of the buffer:
Inside GetData
Return value of GetData
Argument of constructor
Member
The compiler by doing RVO/NRVO can merge 1 and 2 into a single object. Moreover it can merge those two objects with 3 by placing the three objects in the same memory location. What it cannot do is place that object and 4 in the same memory address (in the general case).
On that particular copy, you might elide it by default initializing the internal member vector (usually no cost) and swapping the contents of the argument with the member:
explicit Bar( Buffer buffer ) // pass by value if your compiler optimizes it
: buffer_() // default construct: no cost
{
buffer_.swap( buffer ); // swap: no cost
};
Also note that this is the whole reason for rvalue references in the upcoming standard, in C++0x (I know that is not available in VS08) the compiler will use move semantics to avoid the copies while maintaining the code readable (readable as in closest to the intentions than to tricks to avoid the cost).

You will definitely incur a copy for the buffer.
Why do you want to use a shared pointer? Is it a shared data? If so - then go for it. If not - than you have to copy. We don't really know what is your design, do we?

If you're sensitive to copy operations, you may want to force copy operations to be explicit or even prevent them altogether. If you make the copy constructor and assignment operator protected/private (or use boost::noncopyable) the compiler will produce an error whenever it tries to generate code that copies the object. Of course if you do want to make copies sometimes you'll need to provide a method for explicitly doing so, but that ensures that you never accidentally introduce a copy operation.

Related

C++ force dynamic allocation with unique_ptr?

I've found out that unique_ptr can point to an already existing object.
For example, I can do this :
class Foo {
public:
Foo(int nb) : nb_(nb) {}
private:
int nb_;
};
int main() {
Foo f1(2);
Foo* ptr1(&f1);
unique_ptr<Foo> s_ptr1(&f1);
return 0;
}
My question is :
If I create a class with unique_ptr< Bar > as data members (where Bar is a class where the copy constructor was deleted) and a constructor that takes pointers as argument, can I prevent the user from passing an already existing object/variable as an argument (in that constructor) (i.e. force him to use the new keyword) ?
Because if he does, I won't be able to guarantee a valide state of my class objects (the user could still modify data members with their address from outside of the class) .. and I can't copy the content of Bar to another memory area.
Example :
class Bar {
public:
Bar(/* arguments */) { /* data members allocation */ }
Bar(Bar const& b) = delete;
/* Other member functions */
private:
/* data members */
};
class Bar_Ptr {
public:
Bar_Ptr(Bar* ptr) {
if (ptr != nullptr) { ptr_ = unique_ptr<Bar> (ptr); }
} /* The user can still pass the address of an already existing Bar ... */
/* Other member functions */
private:
unique_ptr<Bar> ptr_;
};
You can't prevent programmers from doing stupid things. Both std::unique_ptr and std::shared_ptr contain the option to create an instance with an existing ptr. I've even seen cases where a custom deleter is passed in order to prevent deletion. (Shared ptr is more elegant for those cases)
So if you have a pointer, you have to know the ownership of it. This is why I prefer to use std::unique_ptr, std::shared_ptr and std::weak_ptr for the 'owning' pointers, while the raw pointers represent non-owning pointers. If you propagate this to the location where the object is created, most static analyzers can tell you that you have made a mistake.
Therefore, I would rewrite the class Bar_ptr to something like:
class Bar_ptr {
public:
explicit Bar_ptr(std::unique_ptr<Bar> &&bar)
: ptr(std::move(bar)) {}
// ...
}
With this, the API of your class enforces the ownership transfer and it is up to the caller to provide a valid unique_ptr. In other words, you shouldn't worry about passing a pointer which isn't allocated.
No one prevents the caller from writing:
Bar bar{};
Bar_ptr barPtr{std::unique_ptr<Bar>{&bar}};
Though if you have a decent static analyzer or even just a code review I would expect this code from being rejected.
No you can't. You can't stop people from doing stupid stuff. Declare a templated function that returns a new object based on the templated parameter.
I've seen something similar before.
The trick is that you create a function (let's call it make_unique) that takes the object (not pointer, the object, so maybe with an implicit constructor, it can "take" the class constructor arguments) and this function will create and return the unique_ptr. Something like this:
template <class T> std::unique_ptr<T> make_unique(T b);
By the way, you can recommend people to use this function, but no one will force them doing what you recommend...
You cannot stop people from doing the wrong thing. But you can encourage them to do the right thing. Or at least, if they do the wrong thing, make it more obvious.
For example, with Bar, don't let the constructor take naked pointers. Make it take unique_ptrs, either by value or by &&. That way, you force the caller to create those unique_ptrs. You're just moving them into your member variables.
That way, if the caller does the wrong thing, the error is in the caller's code, not yours.

Policy based approach with logger [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I spend some time with redesigning a logger class I did once into a policy based approach after reading an article about policy based design and wanting to try something myself.
Some code:
template <class Filter, class Formatter, class Outputter>
class LoggerImpl : public LoggerBase {
public:
LoggerImpl(const Filter& filter = Filter(), const Formatter& formatter = Formatter(), const Outputter& outputter = Outputter());
~LoggerImpl();
void log(int channel, int loglevel, const char* msg, va_list list) const;
private:
const Filter mFilter;
const Formatter mFormatter;
const Outputter mOutputter;
};
template <class Filter, class Formatter, class Outputter>
LoggerImpl<Filter, Formatter, Outputter>::LoggerImpl(const Filter& filter, const Formatter& formatter, const Outputter& outputter) :
mFilter(filter), mFormatter(formatter), mOutputter(outputter) {
debuglib::logdispatch::LoggerMgr.addLogger(this);
}
typedef LoggerImpl<NoFilter, SimpleFormatter, ConsoleOutputter> ConsoleLogger;
typedef LoggerImpl<ChannelFilter, SimpleFormatter, VSOutputter> SimpleChannelVSLogger;
typedef LoggerImpl<NoFilter, SimpleFormatter, FileOutputter> FileLogger;
ConsoleLogger c;
SimpleChannelVSLogger a(const ChannelFilter(1));
FileLogger f(NoFilter(), SimpleFormatter(), FileOutputter("log.txt"));
// macro for sending log message to all current created loggers
LOG(1, WARN, "Test %d", 1423);
Depending on the logger I need to pass additional information like the logchannel within the SimpleChannelVsLogger or the filename of the logfile in the FileOututter.
I'm passing the parameters to the constructor of LoggerImpl as const reference and copy them into the object stored in the logger class afterwards.
There is a need to copy them because the lifetime extension is not transitive through a function argument that occurs when binding the temporary created object to a const reference (more on this here: Does a const reference prolong the life of a temporary?).
So first thing here: If I don't want to use pointers as I am not interested in runtime allocation when using templates, I guess there is no other solution than copying the temporary created objects in the way like above?
The actual problem in the copying stuff now comes with the FileOutputter:
An ofstream cannot be copied of course, so how can I copy the FileOutputter object containing the stream?
I came up with following solution to overcome this problem:
struct FileOutputter {
// c_tor
FileOutputter() {}
// c_tor
explicit FileOutputter(const char* fname) {
mStream = std::make_shared<std::fstream>(fname, std::fstream::out);
}
// The copy c_tor will be invoked while creating any logger with FileOutputter
// FileLogger f(NoFilter(), SimpleFormatter(), FileOutputter("log.txt"));
// as all incoming paramters from the constructors stack frame are copied into the current instance of the logger
// as copying a file-stream is not permitted and not good under any means
// a shared pointer is used in the copy c_tor
// to keep the original stream until no reference is referring to it anymore
FileOutputter(const FileOutputter& other) {
mStream = other.mStream;
}
~FileOutputter() {
}
void out(const char* msg) const {
*mStream << msg;
}
std::shared_ptr<std::fstream> mStream;
};
Somehow I have to feeling that this seems a bit complex for a "simple logger class", however this may be just a "problem" with the policy based design approach in this case.
Any thoughts are welcome
It is correct that you should copy the objects if you are going to store them as members in your class.
Storing references is dangerous as it is possible to pass temporary objects as parameters to your ctor, which will lead to dangling references when the temporaries are destructed.
Passing the parameters as pointers is an alternative, but this aproach is also problematic as it then becomes possible to pass in a nullptr (NULL-value), and you have to check for this.
Another alternative would be to move the values i.e. pass the parameters as r-value references. This will avoid copying, however it will require the client to either pass temporaries or std::move objects when calling the ctor. It would no longer be possible to pass l-value references.
// Define ctor as taking r-value references.
template <class Filter, class Formatter, class Outputter>
LoggerImpl<Filter, Formatter, Outputter>::LoggerImpl(Filter&& filter, Formatter&& formatter, Outputter&& outputter) :
mFilter(std::move(filter)), mFormatter(std::move(formatter)), mOutputter(std::move(outputter)) {
// ...
}
/* ... */
// Calling ctor.
FileLogger f1(NoFilter(), SimpleFormatter(), FileOutputter("log.txt")); // OK, temporaries.
FileOutputter fout("log.txt");
FileLogger f2(NoFilter(), SimpleFormatter(), fout); // Illegal, fout is l-value.
FileLogger f3(NoFilter(), SimpleFormatter(), std::move(fout)); // OK, passing r-value. fout may not be used after this!
If you decide to go with the copy-approach then I recommend to instead pass your parameters by value in the ctor. This will allow the compiler to perform optimizations as copy elision (read: Want Speed? Pass by Value).
template <class Filter, class Formatter, class Outputter>
LoggerImpl<Filter, Formatter, Outputter>::LoggerImpl(Filter filter, Formatter formatter, Outputter outputter) :
mFilter(std::move(filter)), mFormatter(std::move(formatter)), mOutputter(std::move(outputter)) {
// ...
}
Using the above definition: in the best case scenario the compiler will elide the copy and the members will be move constructed (when passing a temporary object).
In the worst case scenario: a copy and a move construction will be performed (when passing an l-value).
Using your version (passing parameters as reference to const), a copy will always be performed as the compiler can not perform optimizations.
For move construction to work, you will have to make sure that the types that are passed as parameters is move constructible (either implicitly or using a declared move ctor). If a type is not move constructible it will be copy constructed.
When it comes to copying the stream in FileOutputter, using std::shared_ptr seems like a good solution, although you should initialize mStream in the initialization list instead of assigning in the ctor body:
explicit FileOutputter(const char* fname)
: mStream(std::make_shared<std::ofstream>(fname)) {}
// Note: Use std::ofstream for writing (it has the out-flag enabled by default).
// There is another flag that may be of interest: std::ios::app that forces
// all output to be appended at the end of the file. Without this, the file
// will be cleared of all contents when it is opened.
A std::ofstream is non-copyable and passing around a smart pointer (make sure to use std::shared_ptr though) is probably the simplest solution in your case and also in my opinion, contrary to what you say, not overy complex.
Another approach would be to make the stream member static, but then every instance of FileOutputter would use the same std::ofstream object and it would not be possible to use parallel logger objects writing to different files etc.
Alternatively you could move the stream as std::ofstream is non-copyable but movable. This would however require you to make FileOutputter movable and non-copyable (and probably LoggerImpl as well), as using a "moved" object, other than its dtor, can result in UB. Making an object that manages move-only types to itself become move-only may make a lot of sense sometimes though.
std::ofstream out{"log.txt"};
std::ofstream out2{std::move(out)} // OK, std::ofstream is moveable.
out2 << "Writing to stream"; // Ok.
out << "Writing to stream"; // Illegal, out has had its guts ripped out.
Also, in the example provided, you don't need to declare a copy ctor or a dtor for FileOutputter, as they will be implicitly generated by the compiler.
You can have the policy classes contain static functions so ideally you would want FileOutputter to look like:
template<std::string fileName>
struct FileOutputter {
static void out(const char* msg) const {
std::ofstream out(fileName);
out << msg;
}
};
You would create an instance of LoggerImpl like this
LoggerImpl<NoFilter, SimpleFormatter, FileOutputter<"log.txt"> > FileLogger;
This would mean your LoggerImpl doesn't need to store a copy of the policy classes it just need to call their static functions.
Unfortunately this won't work because you can't have strings as template arguments but you can build a table of strings and pass the index of the filename in your string table. So again you would ideally want this to look like:
//This class should be a singleton
class StringManager
{
std::vector<std::string> m_string;
public:
void addString(const std::string &str);
const std::string &getString(int index);
int getIndexOf(const std::string &str);
};
Then your FileLogger would get an int as a template parameter and it would be the index of the string in the StringManager. This also wouldn't quite work because you need the index available at compile time and StringManager would be initialized at run time. So you would have to build the string table manually and manually write in the index of your string. so your code would look like (after you make StringManager a singleton:
StringManager::instance()->addString("a");
StringManager::instance()->addString("b");
StringManager::instance()->addString("c");
StringManager::instance()->addString("d");
StringManager::instance()->addString("log.txt");
LoggerImpl<NoFilter, SimpleFormatter, FileOutputter<4> > FileLogger;
You would have to make sure that StringManager is fully initialized before the first instance of FileLogger is created.
It's a little ugly but using templates with strings is a little ugly.
You could also do something like:
template <class FilenameHolder>
struct FileOutputter {
static void out(const char* msg) const {
std::ofstream out(FilenameHolder::fileName());
out << msg;
}
};
class MyFileNameHolder
{
static std::string fileName() {return "log.txt";}
};

Default Initialize or Check For Null

I'd like to know is it better to specify a default initialization for a smart-pointer or do a NULL value check before accessing the smart-pointers methods?
Currently I've been using the method below to avoid calling increment() on a NULL pointer. Is this a reasonable way of doing things or is there a pitfall that I don't see?
Note: We use a custom smart-pointer class and I don't have the Boost libraries on my current configuration to test compile this code. This should compile, but YMMV.
Example.h
#include <boost/shared_ptr.hpp>
class Foo
{
public:
Foo() : mFoo(0) {}
Foo(int rawValue) : mFoo(rawValue) {}
void increment() { mFoo++; }
private:
int mFoo;
};
typedef boost::shared_ptr<Foo> FooSP;
class MyClass
{
public:
MyClass() : mFoo(new Foo()) {}
FooSP foo() { return mFoo; }
void setFoo(FooSP newFoo) { mFoo = newFoo; }
private:
FooSP mFoo;
};
Main.cpp
#include <Example.h>
int main()
{
MyClass temp; // Default-constructed
temp.foo()->increment(); // Increment Foo's member integer
// Before: mFoo = 0
// After: mFoo = 1
FooSP tempFoo = new Foo(10); // Create a Foo with a default size
temp.setFoo(FooSP(new Foo(10))); // Explicitly set the FooSP member
temp.foo()->increment(); // Increment the new FooSP
// Before: mFoo = 10
// After: mFoo = 11
return 0;
}
If you are using a smart pointer as a general replacement for a pointer type, you cannot get away from a check for null. This is because a class defined with a smart pointer with a default constructor is likely to allow the smart pointer to be created with its default constructor. Dynamically creating a new object just to fill the pointer until you can set it seems to be a waste of resources.
shared_ptr's constructor is explicit, so your initialization of tempFoo won't compile. If you wanted to save a line of code, you can avoid declaring the temporary like this:
temp.setFoo(FooSP(new Foo(10)));
You can also declare the method of setFoo to take a constant reference, to avoid manipulating the reference count when taking in the parameter.
void setFoo(const FooSP &newFoo) { mFoo = newFoo; }
Or use swap on the parameter instance.
void setFoo(FooSP newFoo) { std::swap(mFoo, newFoo); }
If I were required to implement something along the lines of what you are proposing, I would create a static instance of Foo to serve as the null version, and then have the increment method throw an exception if it was the null version.
class Foo
{
public:
static Foo Null;
//...
void increment() {
if (this == &Null) throw Null;
mFoo++;
}
//...
};
struct DeleteFoo {
void operator () (Foo *t) const {
if (t != &Foo::Null) delete t;
}
};
class MyClass
{
public:
MyClass() : mFoo(&Foo::Null, DeleteFoo()) {}
//...
};
Note the custom deleter for FooSP to properly deal with Foo::Null.
is it better to specify a default initialization for a smart-pointer or do a NULL value check before accessing the smart-pointers methods?
There is no right answer which applies to every case (more soon). If I had to err to one or the other, I would err toward NULL testing without default initialization because that's an obvious programmer error which can be detected and corrected easily.
However, I think the right answer is that there are good reasons we use multiple idioms for construction and initialization, and that you should choose the best approach for your program.
Typically, I will be explicit (no default or no default initialization) in the lower level classes, as well as complex higher level classes. When the classes are mid-level and defaults and ownership are more obvious (often because of limited use cases), then a default may be sensible.
Often, you will just want to be consistent, to avoid surprising clients. You'll also need to be aware of the complexity of allocating default-initialized objects. If it's big and complex to create, and a default does not make sense, then you are simply wasting a lot of resources when the default-constructed object is the wrong choice.
a) do not apply a default where it does not make sense. the default should be obvious.
b) avoid wasted allocations.
In addition to the approaches you have mentioned, there are a few other angles you might also consider:
Matching Foo's declared constructors in MyClass. At least, the ones which pertain to MyClass.
If copyable and efficient to copy, passing a Foo to MyClass's constructor.
Passing Foo in a container (smart pointer in this case) to MyClass's constructor to remove any ambiguity and to offer the client the option to construct (and share, in the case of a shared pointer) Foo as they desire.
Is this a reasonable way of doing things or is there a pitfall that I don't see?
Wasted allocations. Surprising results. It can restrict capabilities. The most obvious, broadly applicable problems are time and resource consumption.
To illustrate some scenarios:
say Foo reads a 1MB file every time it is constructed. when construction parameters are necessary and the default is not the right option, the file would have to be read a second time. the innocent default would double the disk io required.
in another case, an omitted construction parameter may be another large or complex shared pointer. if absent, Foo may create its own -- when the resource could/should have been shared.
Constructors parameters are often very important, and often should not be erased from the interface. It's certainly fine to do so in some cases, but these conveniences can introduce a lot of restrictions or introduce much unnecessary allocations and CPU time as the contained object's complexity increases.
Using both approaches in your programs is fine. Using additional approaches I outlined is also fine. Specifically, using the right approach for the problem is ideal - there are multiple ways to implement ideal solutions available; you just have to determine what that is in the context of what it is your program is trying to do. All these approaches have separate pros and cons - there is often an ideal match for the context of your program's operation and exposed interfaces.

RAII - Class Pointers and Scope

I want to gain a better understanding of how to implement the RAII idiom with my classes, through an example: What the recommended method is for ensuring pointers are free()'d properly in my class?
I have a class which should exist for the duration of the program. In the spirit of RAII and because I need to pass a reference to this class to other classes, I am holding it in a shared_ptr (not sure it actually needs to be held in a shared_ptr, but for fun, it is).
In the class ctor, I use 2 buffers (pointers) and then loop multiple times malloc()'ing, using the buffer and then free()'ing. The dtor should contain failsafe code to free the buffers, in the event of mishap.
The only way the dtor can see the buffers is if I declare them as class variables, however they are only used in the class ctor.
Example:
class Input
{
private:
PSOMETYPE buffer1;
public:
Input();
~Input();
}
Input::Input() : buffer1(NULL)
{
for(blahblah)
{
buffer1 = (PSOMETYPE)malloc(sizeof(SOMETYPE));
// Do work w/buffer1
if(buffer1 != NULL) { free(buffer1); buffer1 = NULL }
}
}
Input::~Input()
{
if(buffer1 != NULL) { free(buffer1); buffer1 = NULL }
}
Considering I only use the buffer in the ctor, does it make sense to declare it as a private class variable? If I declare it in the scope of the ctor, the dtor will have no knowledge as to what it is to free.
I know this is a trivial example, and honestly I could implement this as easily forgetting about using a smart pointer to reference my class and having a blank dtor, just free()'ing as I'm doing inside the loop. I have no mentor or schooling, and I'm uncertain of when the RAII idiom should be followed.
The spirit of RAII would be to use a local object to manage the locally allocated object, rather than artificially tying its lifetime to the object being constructed:
class Input
{
// no pointer at all, if it's only needed in the constructor
public:
Input();
// no explicit destructor, since there's nothing to explicitly destroy
};
Input::Input()
{
for(blahblah)
{
std::unique_ptr<SOMETYPE> buffer1(new SOMETYPE);
// or, unless SOMETYPE is huge, create a local object instead:
SOMETYPE buffer1;
// Do work w/buffer1
} // memory released automatically here
}
You should only ever have to use delete (or free, or whatever) yourself if you're writing a class whose purpose is to manage that resource - and usually there's already a standard class (such as a smart pointer or a container) that does what you want.
When you do need to write your own management class, always remember the Rule of Three: if your destructor deletes something, then the default copying behaviour of the class will almost certainly cause a double delete, so you need to declare a copy constructor and copy-assignment operator to prevent that. For example, with your class I could write the following incorrect code:
{
Input i1; // allocates a buffer, holds a pointer to it
Input i2(i1); // copies the pointer to the same buffer
} // BOOM! destroys both objects, freeing the buffer twice
The simplest way to prevent this is to delete the copy operations, so code like that will fail to compile:
class Input {
Input(Input const&) = delete; // no copy constructor
void operator=(Input) = delete; // no copy assignment
};
Older compilers may not support = delete; in which case you can get almost the same effect by declare them privately without = delete, and not implementing them.

which is better: a lying copy constructor or a non-standard one?

I have a C++ class that contains a non-copyable handle. The class, however, must have a copy constructor. So, I've implemented one that transfers ownership of the handle to the new object (as below),
class Foo
{
public:
Foo() : h_( INVALID_HANDLE_VALUE )
{
};
// transfer the handle to the new instance
Foo( const Foo& other ) : h_( other.Detach() )
{
};
~Foo()
{
if( INVALID_HANDLE_VALUE != h_ )
CloseHandle( h_ );
};
// other interesting functions...
private:
/// disallow assignment
const Foo& operator=( const Foo& );
HANDLE Detach() const
{
HANDLE h = h_;
h_ = INVALID_HANDLE_VALUE;
return h;
};
/// a non-copyable handle
mutable HANDLE h_;
}; // class Foo
My problem is that the standard copy constructor takes a const-reference and I'm modifying that reference. So, I'd like to know which is better (and why):
a non-standard copy constructor:
Foo( Foo& other );
a copy-constructor that 'lies':
Foo( const Foo& other );
Edit:
DuplicateHandle() only works on specific types of handles. This is not one of them. This handle cannot be duplicated, copied, or cloned.
Several people have pointed out that I was mistaken in suggesting it is a non-standard copy constructor and that std::auto_ptr does this. I think that's probably the way to go. But, I end up with warnings every time I use the class when I make the copy ctor take a non-const value. For example:
namespace detail {
class Foo { ... };
};
class Buzz
{
public:
typedef detail::Foo Fuzz;
Fuzz bar() const { return Fuzz(); }; // warning here
};
warning C4239: nonstandard extension used : 'argument' : conversion from 'Foo' to 'Foo &'
1> A non-const reference may only be bound to an lvalue; copy constructor takes a reference to non-const
Can anybody suggest what I should do about them?
Edit2:
Everybody seems to be steering me towards std::auto_ptr<>'s method of doing things. So, I looked there and it uses an intermediate structure to get around the issue I described in the first edit. This is the solution I came up with.
class Foo;
struct Foo_ref
{
explicit Foo_ref( Foo& other ) : ref_( other ) {};
Foo& ref_;
private:
const Foo_ref& operator=( const Foo_ref& );
}; // struct Foo_ref
class Foo
{
public:
Foo() : h_( INVALID_HANDLE_VALUE )
{
};
// transfer the handle to the new instance
Foo( Foo_ref other ) : h_( other.ref_.Detach() )
{
};
~Foo()
{
if( INVALID_HANDLE_VALUE != h_ )
CloseHandle( h_ );
};
operator Foo_ref()
{
Foo_ref tmp( *this );
return tmp;
};
// other interesting functions...
private:
/// disallow assignment
const Foo& operator=( const Foo& );
HANDLE Detach()
{
HANDLE h = h_;
h_ = INVALID_HANDLE_VALUE;
return h;
};
/// a non-copyable handle
HANDLE h_;
}; // class Foo
It compiles cleanly on warning level 4 and seems to work. Please, let me know if it is somehow more irresponsible than my original post.
Both are horrible. If your class has a member variable which is noncopyable, then your class is noncopyable.
If having your class be noncopyable is really unacceptable, one work around is to have a shared pointer to a "state" class/struct to store noncopyable objects (which itself is noncopyable), but your classes can copy the shared pointer around via the standard copy constructor.
The first option has a well established precedent in the form of auto_ptr:
http://www.cplusplus.com/reference/std/memory/auto_ptr/auto_ptr/
auto_ptr gives up its pointer and is reset when it is copied.
The standard that ensures that a function doesn't change arguments passed as const is much stronger than the copy-ctor standard which is really not very formal.
Also, manipulating a const value by casting away its constness is undefined behavior according to the standard. You can do it if either you are certain that the reference refers to a non-const object or you are passing a const object to a (const-incorrect) function that will not modify the value.
Your class is basically doing what std:;auto_ptr does. The copy constructor for auto_ptr looks like:
auto_ptr( auto_ptr & p );
which means it cannot be used in certain situations, like in standard containers. This is probably best practice, but its noticeable that auto_ptr has been deprecated in C++0x.
Maybe the copy constructor should just use DuplicateHandle() to make a real copy.
Well, if you truly need a copy constructor, then you must ensure that it has proper semantics. If you implement either of your approaches, then you're asking for trouble. Code that depends on your copy constructor will not know about your transfer of ownership scheme, and this can have unpredictable results. (This is the reason, for example, that you can't use a std::auto_ptr in an STL container.)
If you don't really need a copy constructor, then create a method that copies the object and transfers handle ownership.
If you do need a copy constructor, then you need a way to share the handle between copies. I would suggest using an auxiallary object to store the handle and a reference count, so you know when to close the handle. I'd also re-examine your assumption that the handle is non-copyable. If the only issue is that you must close it exactly once, then you can work around the problem by using the DuplicateHandle() function.
One final note: I'd say that a cardinal rule in programming is never lie about what a function does.
Perhaps, instead of using a non-standard or wierd copy constructor for an object which is non-copyable, you should consider not copying it. You could use the new shared_ptr machinery or unique_ptr to do ownership handoff instead of worrying about this stuff yourself.
Using a non-const copy constructor is quite OK. I don’t know why you call it “non-standard”. The standard clearly says (§12.8/2) that the copy constructor argument doesn’t have to be const. It just usually is, because modifying the other object is rarely necessary and has its disadvantages (e.g. cannot be used in standard containers).
But I would rather revisit the design: do you really need to copy an object that’s clearly noncopyable? The semantics say otherwise. Alternatively, can’t you copy the underlying handle in a safe way?
Either just assign it and use shared ownership semantics, perhaps together with a reference counter so you don’t close the handle twice, or too early.
Or cause the underlying object of the handle to be duplicated.
I definitely would not implement the copy constructor as you have here. The Detach method is declard as const but really isn't. It would be better to make the copy constructor follow the standard form but make it private and/or make it throw on invocation. Then, you could provide a Clone method that duplicates the handle and any other applicable attributes.
That's easy: a non-standard one. A constructor that modifies its const parameter would be very difficult to predict by the developer. You'd need it to be documented and the developer would need to know to look at the documentation for a very common use....something most won't do.
A non-standard constructor though begs attention.
Besides, this is how the standard does it with auto_ptr. Why? So you can't accidentally put it in a container. Another good reason to use the non-standard version.
As for your edit question: It's not that you're passing a non-const object, it's that you're trying to copy a non-const temporary, which isn't allowed to be passed by non-const reference. You can just declare an actual object and that should correct it.
Fuzz bar() const { Fuzz fuzz; return fuzz; };
The easiest solution is to replace the HANDLE h with a boost::shared_ptr<HANDLE> ph. Now add a private convenience function HANDLE h() { return *ph; }. As a result, the default copy ctor will do the right thing.
Sure, you might have some problems if both objects try to use the handle at the same time. But since your original design left the original object without a handle, this appears to be not the case for you anyway.