Assume I have a non-copyable class with multiple constructors with like this
class Foo: boost::noncopyable
{
public:
Foo(std::string s) {...}; // construct one way
Foo(int i) {...}; // construct another way
}
Now, I want to construct an object, and choose which constructor to use at runtime:
I could do it with pointers like this:-
boost::shared_ptr<Foo> f;
if (condition)
f.reset(new Foo(myString));
else
f.reset(new Foo(myInteger));
// common code follows
f->doSomethingComplicated(...);
But that feels messy and slow. Is there an easy way to choose the constructor for the object without resorting to dynamic allocation?
Some more details : The Foo class above is simply to illustrate the problem.The actual class involved is Windows Gdiplus::Bitmap - http://msdn.microsoft.com/en-gb/library/windows/desktop/ms534420(v=vs.85).aspx
You can do it with C++11 on stack, without placement new and without copy/move constructor/assignment available. Observe:
auto factory = [&]() -> Foo
{
if (condition) {
return { myString };
} else {
return { myInteger };
}
};
Foo&& foo = factory();
foo.doSomethingComplicated();
The functor and the Foo instance will live happily on stack, no allocations made (except for copying string in Foo's constructor, probably). Foo will get its destructor called when it gets out of scope. Win.
When using uniform initialization to construct return value, no copy/move operation is involved. Note that returning myString (implicit conversion) or Foo(myString) would force compiler to check if object is copyable/moveable, even if such copy/move could be elided.
Edit: alternatively, this can be made even shorter, but bit more "magical":
Foo&& foo = [&]() -> Foo
{
if (condition) {
return { myString };
} else {
return { myInteger };
}
}();
Edit: Pre-C++11, Visual Studio hacky solution:
VC doesn't seem to check whether object is copyable when resorting on implicit conversion constructors to return value from a function. So this is valid, even though it's against the standard:
Foo make_foo(bool condition, const std::string&s, int i)
{
if ( condition) {
return s;
} else {
return i;
}
}
Then just use it like that:
Foo& f = make_foo(condition, myString, myInteger);
Note that this is yet another VC hack, as according to standard temporary can't be assigned to a reference to a mutable object, i.e. it would need to be changed const Foo&, which would be quite limiting here.
Not saying that you should handle it this way, but it is possible.
You have a flaw in your design. The 'Foo' is delegating the type elision to the user of the class. Have a look at boost::any (http://www.boost.org/doc/libs/1_55_0/doc/html/any.html)
I think the best option that meets your requirements (not dynamically allocated, not-copyable, pre-C++11) would be to use the placement new.
See here for a short example.
boost::optional might also be an acceptable option for you (it basically just does this for you internally, as well as keeping track of whether the object has been initialized). The in-place construction is a bit messy though for optional imo.
Keep it small and simple, I'd say. If this is a very local problem, why not just repeat the call?
if (condition)
{
Foo f(myString);
f.doSomethingComplicated();
}
else
{
Foo f(myInt);
f.doSomethingComplicated();
}
If that does not prove feasible, wrap a Foo pointer (or smart pointer) in a new class.
class FooWrapper // copyable
{
private:
boost::shared_ptr<Foo> m_foo;
public:
FooWrapper(std::string const &s) : m_foo(new Foo(s)) {}
FooWrapper(int i) : m_foo(new Foo(i)) {}
void doSomethingComplicated() { m_foo->doSomethingComplicated(); }
};
FooWrapper foo = condition ? FooWrapper(myString) : FooWrapper(myInt);
foo.doSomethingComplicated();
Using C++11 you can do:
Foo&& f = condition ? Foo{myInteger} : Foo{myString};
f.doSomethingComplicated();
By using an r-value reference you avoid the constness and still extend the lifetime of the temporary.
If you only need to construct a temporary object, I think you can bind it to a const reference using a ternary expression:
const Foo &f(condition ? Foo(myString) : Foo(myInteger));
f.doSomethingComplicated(...);
Related
Let's say I have Foo class:
struct Resource {
void block();
void unblock();
};
struct Foo {
static Foo create() {
Resource resource;
resource.block();
return Foo{resource};
}
~Foo() { resource.unblock(); }
void f() {}
private:
Resource resource;
Foo(Resource resource): resource(resource) {}
};
Am I right and there is no guarantee that ~Foo will be called only once in such block?
{
Foo foo = Foo::create();
foo.f();
}
If there is no guarantee, is it possible to fix somehow if using c++11 and move semantic? For example not call unblock_resource in moved foo, but I am not sure is there guarantee to use move constructor/operator= in return from Foo::create?
Copy elision won't help you, since it is an optimization and may or may not be applied.
Move semantics do help, and you get guaranteed moves in function return of local variables. But that means you have to write the move constructor, and you have to modify the destructor so that it doesn't unlock the resource of an object that was moved from.
Not sure about how this is related to the factory pattern, but to answer your question "Am I right and there is no guarantee that ~Foo will be called only once in such block?":
Avoiding copying/moving objects used as return values (i.e. return value optimization, especially named return value optimization) is permitted, but not guaranteed:
Under the following circumstances, the compilers are permitted, but
not required to omit the copy- and move- (since C++11)construction of
class objects even if the copy/move (since C++11) constructor and the
destructor have observable side-effects. This is an optimization: even
when it takes place and the copy-/move-constructor is not called, it
still must be present and accessible (as if no optimization happened
at all), otherwise the program is ill-formed:
If a function returns a class type by value, and the return
statement's expression is the name of a non-volatile object with
automatic storage duration, which isn't a function parameter, or a
catch clause parameter, and which has the same type (ignoring
top-level cv-qualification) as the return type of the function, then
copy/move (since C++11) is omitted. When that local object is
constructed, it is constructed directly in the storage where the
function's return value would otherwise be moved or copied to. This
variant of copy elision is known as NRVO, "named return value
optimization".
One way could be to control locking/unlocking resources in the move constructor and the destructor, just as you mentioned in your question.
Another way could be to make use of shared_ptr, such that creation and deletion of your Foo-object is managed by an RAII-style shared_ptr wrapper. There is just one tricky thing if you want to keep the Foo-constructor private, since make_shared cannot deal with private constructors. To overcome this, you could declare a public constructor taking a parameter of a private data type as parameter. A little bit ugly, and maybe a little bit clumsy due to the shared_ptr-wrapper. But maybe it's at least some inspiration:
struct Foo {
private:
struct private_dummy {};
public:
static shared_ptr<Foo> create() {
shared_ptr<Foo> foo = make_shared<Foo>(private_dummy{});
return foo;
}
~Foo() { cout << "deleted."; }
Foo(struct private_dummy x) { cout << "created."; }
};
void test() {
shared_ptr<Foo> foo = Foo::create();
}
int main() {
test();
//Foo notOK();
}
Rule of 3/5/0. You define a destructor, but not copy / move constructors / assignment operators, which is a red flag that your type is unsafe. Indeed, the destructor may get called twice prior to C++17, and it's easy to mess up while using it even post C++17.
I recommend using std::unique_ptr so that you don't define any copy/move operations or the destructor. You can use std::unique_ptr even if the resource you are managing isn't a pointer; it'd look something like this:
class Resource {
int handle;
public:
Resource(std::nullptr_t = nullptr)
: handle{}
{}
Resource(int handle)
: handle{ handle }
{}
explicit operator bool() const { return handle != 0; }
friend bool operator==(Resource lhs, Resource rhs) { return lhs.handle == rhs.handle; }
friend bool operator!=(Resource lhs, Resource rhs) { return !(lhs == rhs); }
void block() { std::cout << "block\n"; }
void unblock() { std::cout << "unblock\n"; }
struct Deleter {
using pointer = Resource;
void operator()(Resource resource) const {
resource.unblock();
}
};
};
struct Foo {
static Foo create() {
Resource resource{42};
resource.block();
return Foo{resource};
}
void f() {}
private:
std::unique_ptr<Resource, Resource::Deleter> resource;
Foo(Resource resource): resource(resource) {}
};
You are looking for copy-elision.
In short, your code is guaranteed to work in C++17, as described at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html
In C++14 and before there is no such guarantee.
Copy elision is an optimization that existed before C++11 and allowed compiler to omit copy constructor call in some cases.
C++11 has added move semantics and copy elision was expanded to allow compiler to avoid moving or copying (if moving is not available) an object.
Regardless of what compiler actually does, your class must still provide copy or move constructor, even if one will not be used by the compiler.
C++17 introduces "guaranteed copy-elision", which allows you to return objects of non-movable classes, just like in your case. Note that proposal explicitly mentions "factory functions". Quote:
it is impossible or very difficult to write factory functions
Example from proposal has this example:
struct NonMoveable {
NonMoveable(int);
NonMoveable(NonMoveable&) = delete;
void NonMoveable(NonMoveable&) = delete;
std::array<int, 1024> arr;
};
NonMoveable make() {
return NonMoveable(42); // ok, directly constructs returned object
}
As of today, both Clang and GCC are able to compile that code with -std=c++17 flag, but not with -std=c++14.
I see two ways for you to solve this problem:
Use C++17: I recommend deleting both copy and move constructor (and operator=) to make sure your code will not compile under earlier standard with buggy effects.
Rely only on things that are available in C++14 to make your code work everywhere. You might want add additional state to your object, delete copy constructor and implement move constructor.
This is an example of how it can be done in C++14.
class Foo {
public:
Foo() = default;
Foo(const Foo &) = delete;
Foo(Foo &&rvalue) noexcept { std::swap(blocked, rvalue.blocked); }
~Foo() { if (blocked) unblock();
void block() { blocked = true; }
void unblock() { blocked = false; }
private:
bool blocked{false};
};
(possibly related to How to implement a C++ method that creates a new object, and returns a reference to it which is about something different, but incidentially contains almost exactly the same code)
I would like to return a reference to a static local from a static function. I can get it to work, of course, but it's less pretty than I'd like.
Can this be improved?
The background
I have a couple of classes which don't do much except acquire or initialize a resource in a well-defined manner and reliably, and release it. They don't even need to know an awful lot about the resource themselves, but the user might still want to query some info in some way.
That's of course trivially done:
struct foo { foo() { /* acquire */ } ~foo(){ /* release */ } };
int main()
{
foo foo_object;
// do stuff
}
Trivial. Alternatively, this would work fine as well:
#include <scopeguard.h>
int main
{
auto g = make_guard([](){ /* blah */}, [](){ /* un-blah */ });
}
Except now, querying stuff is a bit harder, and it's less pretty than I like. If you prefer Stroustrup rather than Alexandrescu, you can include GSL instead and use some concoction involving final_act. Whatever.
Ideally, I would like to write something like:
int main()
{
auto blah = foo::init();
}
Where you get back a reference to an object which you can query if you wish to do that. Or ignore it, or whatever. My immediate thought was: Easy, that's just Meyer's Singleton in disguise. Thus:
struct foo
{
//...
static bar& init() { static bar b; return b; }
};
That's it! Dead simple, and perfect. The foo is created when you call init, you get back a bar that you can query for stats, and it's a reference so you are not the owner, and the foo automatically cleans up at the end.
Except...
The issue
Of course it couldn't be so easy, and anyone who has ever used range-based for with auto knows that you have to write auto& if you don't want surprise copies. But alas, auto alone looked so perfectly innocent that I didn't think of it. Also, I'm explicitly returning a reference, so what can auto possibly capture but a reference!
Result: A copy is made (from what? presumably from the returned reference?) which of course has a scoped lifetime. Default copy constructor is invoked (harmless, does nothing), eventually the copy goes out of scope, and contexts are released mid-operation, stuff stops working. At program end, the destructor is called again. Kaboooom. Huh, how did that happen.
The obvious (well, not so obvious in the first second!) solution is to write:
auto& blah = foo::init();
This works, and works fine. Problem solved, except... except it's not pretty and people might accidentially just do it wrong like I did. Can't we do without needing an extra ampersand?
It would probably also work to return a shared_ptr, but that would involve needless dynamic memory allocation and what's worse, it would be "wrong" in my perception. You don't share ownership, you are merely allowed to look at something that someone else owns. A raw pointer? Correct for semantics, but... ugh.
By deleting the copy constructor, I can prevent innocent users from running into the forgot-& trap (this will then cause a compiler error).
That is however still less pretty than I would like. There must be a way of communicating "This return value is to be taken as reference" to the compiler? Something like return std::as_reference(b);?
I had thought about some con trick involving "moving" the object without really moving it, but not only will the compiler almost certainly not let you move a static local at all, but if you manage to do it, you have either changed ownership, or with a "fake move" move-constructor again call the destructor twice. So that's no solution.
Is there a better, prettier way, or do I just have to live with writing auto&?
Something like return std::as_reference(b);?
You mean like std::ref? This returns a std::reference_wrapper<T> of the value you provide.
static std::reference_wrapper<bar> init() { static bar b; return std::ref(b); }
Of course, auto will deduce the returned type to reference_wrapper<T> rather than T&. And while reference_wrapper<T> has an implicit operatorT&, that doesn't mean the user can use it exactly like a reference. To access members, they have to use -> or .get().
That all being said however, I believe your thinking is wrong-headed. The reason is that auto and auto& are something that every C++ programmer needs to learn how to deal with. People aren't going to make their iterator types return reference_wrappers instead of T&. People don't generally use reference_wrapper in that way at all.
So even if you wrap all of your interfaces like this, the user still has to eventually know when to use auto&. So really, the user hasn't gained any safety, outside of your particular APIs.
Forcing the user to capture by reference is a three-step process.
First, make the returned thing non-copyable:
struct bar {
bar() = default;
bar(bar const&) = delete;
bar& operator=(bar const&) = delete;
};
then create a little passthrough function that delivers references reliably:
namespace notstd
{
template<class T>
decltype(auto) as_reference(T& t) { return t; }
}
Then write your static init() function, returning decltype(auto):
static decltype(auto) init()
{
static bar b;
return notstd::as_reference(b);
}
Full demo:
namespace notstd
{
template<class T>
decltype(auto) as_reference(T& t) { return t; }
}
struct bar {
bar() = default;
bar(bar const&) = delete;
bar& operator=(bar const&) = delete;
};
struct foo
{
//...
static decltype(auto) init()
{
static bar b;
return notstd::as_reference(b);
}
};
int main()
{
auto& b = foo::init();
// won't compile == safe
// auto b2 = foo::init();
}
Skypjack noted correctly that init() could be written just as correctly without notstd::as_reference():
static decltype(auto) init()
{
static bar b;
return (b);
}
The parentheses around the return (b) force the compiler to return a reference.
My problem with this approach is that c++ developers are often surprised to learn this, so it could be easily missed by a less experienced code maintainer.
My feeling is that return notstd::as_reference(b); explicitly expresses intent to code maintainers, much as std::move() does.
The best, most idiomatic, readable, unsurprising thing to do would be to =delete the copy constructor and copy assignment operator and just return a reference like everybody else.
But, seeing as you brought up smart pointers...
It would probably also work to return a shared_ptr, but that would involve needless dynamic memory allocation and what's worse, it would be "wrong" in my perception. You don't share ownership, you are merely allowed to look at something that someone else owns. A raw pointer? Correct for semantics, but... ugh.
A raw pointer would be perfectly acceptable here. If you don't like that, you have a number of options following the "pointers" train of thought.
You could use a shared_ptr without dynamic memory, with a custom deleter:
struct foo {
static shared_ptr<bar> init() { static bar b; return { &b, []()noexcept{} }; }
}
Although the caller doesn't "share" ownership, it's not clear what ownership even means when the deleter is a no-op.
You could use a weak_ptr holding a reference to the object managed by the shared_ptr:
struct foo {
static weak_ptr<bar> init() { static bar b; return { &b, []()noexcept{} }; }
}
But considering the shared_ptr destructor is a no-op, this isn't really any different from the previous example, and it just imposes on the user an unnecessary call to .lock().
You could use a unique_ptr without dynamic memory, with a custom deleter:
struct noop_deleter { void operator()() const noexcept {} };
template <typename T> using singleton_ptr = std::unique_ptr<T, noop_deleter>;
struct foo {
static singleton_ptr<bar> init() { static bar b; return { &b, {} }; }
}
This has the benefit of not needing to manage a meaningless reference count, but again the semantic meaning is not a perfect fit: the caller does not assume unique ownership, whatever ownership really means.
In library fundamentals TS v2 you can use observer_ptr, which is just a raw pointer that expresses the intent to be non-owning:
struct foo {
static auto init() { static bar b; return experimental::observer_ptr{&b}; }
}
If you don't like any of these options, you can of course define your own smart pointer type.
In a future standard you may be able to define a "smart reference" that works like reference_wrapper without the .get() by utilising overloaded operator..
If you want to use singleton, use it correctly
class Singleton
{
public:
static Singleton& getInstance() {
static Singleton instance;
return instance;
}
Singleton(const Singleton&) = delete;
Singleton& operator =(const Singleton&) = delete;
private:
Singleton() { /*acquire*/ }
~Singleton() { /*Release*/ }
};
So you cannot create copy
auto instance = Singleton::getInstance(); // Fail
whereras you may use instance.
auto& instance = Singleton::getInstance(); // ok.
But if you want scoped RAII instead of singleton, you may do
struct Foo {
Foo() { std::cout << "acquire\n"; }
~Foo(){ std::cout << "release\n"; }
Foo(const Foo&) = delete;
Foo& operator =(const Foo&) = delete;
static Foo init() { return {}; }
};
With the usage
auto&& foo = Foo::init(); // ok.
And copy is still forbidden
auto foo = Foo::init(); // Fail.
Someone would make a typo in one day and then we may or may not notice it in so many code, although we all know we should use auto& instead of auto.
The most convenient but very dangerous solution is using a derived class, as it breaks the strict-aliasing rule.
struct foo
{
private:
//Make these ref wrapper private so that user can't use it directly.
template<class T>
class Pref : public T {
private:
//Make ctor private so that we can issue a compiler error when
//someone typo an auto.
Pref(const Pref&) = default;
Pref(Pref&&) = default;
Pref& operator=(const Pref&) = default;
Pref& operator=(Pref&&) = default;
};
public:
static Pref<bar>& init() {
static bar b;
return static_cast<Pref<bar>&>(b);
}
///....use Pref<bar>& as well as bar&.
};
I want to use smart pointers in this way:
using namespace std;
shared_ptr<string> foo;
weak_ptr<string> bar (foo);
foo = make_shared<string>("some string");
cout << *bar.lock(); // SIGSEGV
The clue is how to initialize shared_ptr's object manager without construction the object (string in this case). Is it even possible? I could use default ctor of the object and later use copy/move assignment. But may some more elegant solution exist?
It is worth for me that the object won't be initialized - it would be a lie in logic if I would initialize the shared_ptr with empty value.
Why not do this instead:
shared_ptr<string> foo = make_shared<string>();
weak_ptr<string> bar (foo);
*foo = "some string":
That way you are actually sharing a string. What you described is more like sharing a shared pointer.
I solved my problem. The core of this idea is to use nested pointers: shared_ptr<unique_ptr<MYTYPE>>. In my case I created a wrapping template:
template<typename T>
class LazyInitializator : public std::unique_ptr<T> {
public:
LazyInitializator() : std::unique_ptr<T>() {} // this ctor offers lazy initialization
LazyInitializator(const T& val) : std::unique_ptr<T> (std::make_unique<T>(val)) {} // for normal construction
LazyInitializator& operator= (const T& val) {
if (!std::unique_ptr<T>::operator bool()) // if object wasn't constructed
std::unique_ptr<T>::operator= (std::make_unique<T>(val)); // construct it
**this = val; // use assingment op provided by T - no unneccessary mem allocation
return *this;
}
};
Thanks to it I can use shared_ptrs in easier way. I can do sth like this:
using namespace std;
shared_ptr<LazyInitializator<string>> foo = make_shared<LazyInitializator<string>>();
weak_ptr<LazyInitializator<string>> bar (foo);
*foo = "some string";
cout << **bar.lock();
Yes, I know, looks a bit tricky, but it is the best solution for me now.
Real example is obviously much longer, but this sums up my problem:
class Object
{
int mInt1,mInt2;
Object::Object();
Object::Object(int param1);
Object::Object(int param1, int param2);
};
Object::Object(){}
Object::Object(int param1):mInt1(param1){}
Object::Object(int param1, int param2):mInt1(param1),mInt1(param2){}
Then in main:
if (type1){
Object instance(param1);
}
else{
Object instance(param1,param2);
}
// do stuff with instance
Whoops! That won't work, instance is out of scope for the program that follows.
Object instance;
if (type1){
instance = Object(param1);
}
else{
instance = Object(param1,param2);
}
// do stuff with instance
But now I run in to trouble because I didn't have a copy constructor defined. I'd really rather not write a copy-constructor because my actual class has dozens of members, many of which are non-basic types and might require even more work to copy.
Specifically, I am getting
main.cpp: error: use of deleted function ‘Object& Object::operator=(Object&&)’
instance = Object(param1);
^
note: ‘Object& Object::operator=(Object&&)’ is implicitly deleted because the default definition would be ill-formed:
The universal way to deal with non-copyable objects is to throw it into a unique_ptr (or auto_ptr, depending on your compiler).
std::unique_ptr<Object> instance;
if (type1) {
instance.reset(new Object(i));
}
else {
instance.reset(new Object(i, j));
}
Using raw pointers here really isn't safe because once you start having to deal with exceptions or any interesting code paths it becomes a chore to worry about leaks. Trust me, in 100% of cases, you will have less work and lines of code to deal with if you just drop it in a unique_ptr.
An optimal solution would be to redesign Object's constructors, because circumventing non-copyability may leave the object in an illegal state. In general, you want to preserve non-copyability if the compiler thinks it's necessary. We don't have the details here to flesh out such a solution however.
If you do not want dynamically allocation then you can use an Initialize function:
class Object
{
int mInt1,mInt2;
Object::Object();
Object::Initialize();
Object::Initialize(int param1);
Object::Initialize(int param1, int param2);
};
Object::Object(){Initialize();} //call the empty Initialize for nice coding...:)
Object::Initialize(){ }
Object::Initialize(int param1){ mInt1(param1); }
Object::Initialize(int param1, int param2){ mInt1(param1);mInt1(param2);}
Then you can use initialize to select the type.
Object instance;
if (type1){
instance.Initialize(param1);
}
else{
instance.Initialize(param1,param2);
}
Here is a low-level(ish) solution which does what you want. I will leave it up to you to decide whether it's a good idea to use it:
#include <type_traits>
template <class T>
class MultiInitialiser
{
T *object;
std::aligned_storage<T> storage;
public:
MultiInitialiser() : object(nullptr)
{}
template <class... Arg>
void initialise(Arg &&... arg)
{
if (object)
throw "Double init error";
object = new (&storage) T(std::forward<Arg>(arg)...);
}
operator T& ()
{ return *object; }
operator const T& () const
{ return *object; }
~MultiInitialiser()
{
if (object)
object->~T();
}
};
Copy/move operations for the above are left as an excercise for the reader ;-)
The class would then be used like this:
MultiInitialiser<Object> instance;
if (type1){
instance.initialise(param1);
}
else{
instance.initialise(param1,param2);
}
Apart from the cast to T, you could also give the class operator* and operator-> returning the contained object, similar to what boost::optional does.
There are a couple of options that let you do this while retaining automatic storage, and which one you should use depends on the semantics of the type Object.
The POD
If you have a type like the one given in the question, you might choose to reduce it to a POD type; basically, remove all of the user-provided constructors and give everything the same access specifier:
struct Object {
int mInt1, mInt2;
};
Then, your initialization pattern might look like this (using placement new):
Object o; // Default-initialized, a no-op
if (condition)
new (&o) Object {i};
else
new (&o) Object {i, j};
General Types
Generally speaking, your typical value-semantic type will work perfectly fine if you default-initialize and then assign, thanks to move semantics:
std::vector <foo> v;
if (condition)
v = std::vector <foo> (42);
else
v = std::vector <foo> {bar, baz, quux};
Often, though, you'll still be doing work in the default constructor, because certain types' default-constructed objects (e.g., std::vector) have well-defined state. If you want to avoid this work for an arbitrary predefined type, you might want to use std::optional (as of this writing not actually yet standard):
std::optional <big_but_flat> b;
if (condition)
b.emplace (i);
else
b.emplace (i, j);
Without std::optional
You might object that std::optional has too much overhead associated with it, and I'll leave it to you and your measurements to decide whether that's the case. At any rate, we can get our behaviour without worrying about that overhead— but may the nasal demons have mercy if you don't actually perform your initialization. We'll use a union to get what we want:
// At function scope
union store_v {
std::vector <int> v;
store_v () {}
~store_v () { v.~vector <int> (); }
} sv;
if (condition)
new (&sv.v) std::vector <int> (42);
else
new (&sv.v) std::vector <int> {49, 343, 2401};
This may be improved. For example, we can make the storage a template:
template <typename T>
union store {
T t;
store () {}
~store () { t.~T (); }
};
// At function scope
store <std::vector <int>> sv;
if (condition)
new (&sv.t) std::vector <int> (42);
else
new (&sv.t) std::vector <int> {49, 343, 2401};
We can give ourselves a reference:
template <typename T>
union store {
T t;
store () {}
~store () { t.~T (); }
};
// At function scope
store <std::vector <int>> sv;
auto&& v = sv.t; // Deduce const, for what that's worth
if (condition)
new (&v) std::vector <int> (42);
else
new (&v) std::vector <int> {49, 343, 2401};
And with a little attention to detail to avoid name collisions and handle C++'s… interesting declaration syntax, we could even define a couple of macros to clean the code up (implementation left as an exercise to the reader):
template <typename T>
union store {
T t;
store () {}
~store () { t.~T (); }
};
// At function scope
DECL_UNINIT (std::vector <int>, v);
if (condition)
INIT (v, (42));
else
INIT (v, {49, 343, 2401});
You can use a pointer to your object and instantiate it by new operator:
Object * instance;
if (type1){
instance = new Object(param1);
}
else{
instance = new Object(param1,param2);
}
You're using something that is called copy elision.
This states that the compiler MAY optimize the code and avoid a copy constructor in such a case.
But it doesn't have to, and may use a copy constructor anyway.
The right way (without being subjected to the whims of the compiler) would be to use a pointer:
Object* instance;
if (type1){
instance = new Object(param1);
}
else{
instance = new Object(param1,param2);
}
In your version of one-parameter constructor, the mInt2 member is just ignored (isn't ever initialized), so I assume that you don't do any computation with that member if type1 is false (though I don't know how you're doing it without storing type1).
So, why don't just change the dessign? Make te constructor take int param1, int param2 and type1 as parameters and choose internally how to build himself:
class Object
{
int mInt1,mInt2;
Object::Object() :
mInt1(0), // don't forget to initialize your values!
mInt2(0)
{}
// Object::Object(int param1); no more 1-parameter ctor.
Object::Object(int param1, int param2, type type1) :
mInt1(param1),
mInt2(type1 ? param2 : 0) // assuming that 0 isn't a valid value for mInt2
{}
};
Then in main:
Object instance(param1, param2, type1);
// do stuff with instance
I guess that it looks a little neater.
You could write a move assignment. Depending what your data members look like, you may get away with memcopying some or all of them, cf. Move constructor with memcpy.
That said, I assume that either you need a full set of constructors/destructors, including copy and assignment; that will always be necessary if you want to have it in containers, assign it etc. Or else the class doesn't need any of that and you just initialize the needed parts of it depending on the situation, and when you are done, you de-initialize manually.
I think I found a way to do it without requiring allocating the object on the heap, using a lambda.
Basically, the idea is to separate the construction from the usage. (the following assume that you fixed the difinition of Object so that it compiles)
auto work = []( Object& object ){
// here do the work on the object
};
// now create the object and apply the work in the process:
if (type1){
Object instance(param1);
work( instance );
}
else{
Object instance(param1,param2);
work( instance );
}
Here no copy was involved but the same code is still applied whatever the wy the object was constructed, and without having to declare an external function (as a lambda is a local function).
From the memory point of view, there will always be only one instance object so the stack memory allocated will always be the same size whatever the path.
Obviously, this don't work if the instance have to get out of the scope of the whole function. If it's the case, then you really need to allocate it on the heap using a smart pointer preferably.
I have a type that is copyable, but may be expensive to copy. I have implemented the move constructor and move assignment. But I have performance issues where folks forget to call move() when passing by value.
Is it good C++11 style to remove the copy constructor, and instead provide an explicit copy() method for the rare cases when a copy is actually desired? This is idiomatic in other languages (Ruby, JavaScript) but I don't know of anything in the C++ standard library that prohibits copy purely for performance. For instance, std::vector<> is copyable, while std::unique_ptr<> and std::thread are non copyable for other reasons.
Should a type be move-only, just because copying may be expensive?
No. If the semantics of your type is such that copying it is conceptually meaningful, then the correct way to make copying available is to implement a copy constructor, and give the user a chance to adopt standard syntax for invoking it:
T a;
T a = b;
If people will forget to move from objects they don't want to use anymore... Well, that's their bad:
T c = std::move(a); // I'm doing it right (if I no longer need object a);
T d = b; // If I don't need b anymore, I'm doing it wrong.
And if (for any reason) for some functions of yours it is always desirable that the caller provides an object from which it is possible to move, then let the function accept an rvalue reference:
void foo(my_class&& obj);
my_class a;
foo(a); // ERROR!
foo(std::move(a)); // OK
I would treat the class as non-copyable in signature if copy is sufficiently expensive. Semantically things are copyable only if you want them to be, and an expensive copy is a decent reason to decide "no, not copyable".
The ability for something to be copied does not mean it need be implemented in a type that is copyable. The implementer of that type gets to decide if it should be semantically copyable.
I wouldn't call the operation that produced an expensive copy "copy", but rather "clone" or "duplicate".
For a way you might do this:
#include <utility>
template<typename T>
struct DoCopy {
T const& t;
DoCopy( T const& t_ ):t(t_) {}
};
template<typename T>
DoCopy<T> do_copy( T const& t ) {
return t;
}
struct Foo {
struct ExpensiveToCopy {
int _[100000000];
};
ExpensiveToCopy* data;
Foo():data(new ExpensiveToCopy()) {}
~Foo(){ delete data; }
Foo(Foo&& o):data(o.data) { o.data = nullptr; }
Foo& operator=(Foo&& o) { data=o.data; o.data=nullptr; return *this; }
Foo& operator=(DoCopy<Foo> o) {
delete data;
if (o.t.data) {
data=new ExpensiveToCopy(*o.t.data);
} else {
data=new ExpensiveToCopy();
}
return *this;
}
Foo( DoCopy<Foo> cp ):data(cp.t.data?new ExpensiveToCopy( *cp.t.data ):new ExpensiveToCopy() ) {};
};
int main() {
Foo one;
// Foo two = one; // illegal
Foo three = std::move(one); // legal
Foo four;
Foo five = do_copy(three);
four = std::move(three);
five = do_copy(four);
}
This is somewhat similar to the ways you could have written std::move like semantics prior to the existence of rvalue references, with similar downsides to such techniques, namely that the language itself has no idea what shenanigans you are up to.
It has the advantage that the syntax of the above do_copy is similar to the syntax of std::move, and it allows you to use traditional expressions without having to create trivial instances of Foo then construct a copy of another variable etc.
If the situations where we want to treat it as copyable are common (if to be avoided), I'd write a copy-wrapper around the class that knows about the duplicate method.
No. If the type is copyable then the type is copyable. This means its copy constructor is available and works. It doesn't mean there's some member function whose name looks like the characters c, o, p and y in sequence, that does "sort of nearly a similar thing".