How do ask the compiler if a type has a move constructor?
std::is_move_constructible doesn't apply because it will return true even if the type is copy constructible only.
Is there something that will return whether or not there is actually a user-defined move constructor?
EDIT:
For background, I am trying to create a type erased class that will (given a set of types) decide whether or not it is worth saving off a type erased version of the move constructor.
If at least one of these types does have an "interesting" move constructor (non trivial and actually implemented), then it should save off the move constructor, else it won't and will save space
#include <type_traits>
struct NoMove {
NoMove(NoMove const&) {}
//NoMove(NoMove&&) = delete;
};
struct InterestingMove {
InterestingMove(InterestingMove&&) {}
};
template<typename T>
struct is_interesting_move_constructor :
std::integral_constant<bool,
std::is_move_constructible<T>::value &&
!std::is_trivially_move_constructible<T>::value> {};
// Fails:
//static_assert(!is_interesting_move_constructor<NoMove>::value);
// Is fine:
static_assert(is_interesting_move_constructor<InterestingMove>::value);
The problem with this attempt is that it should return false on NoMove but it doesn't because is_move_constructible doesn't return true based on whether or not there is actually a move constructor
Type erased class sketch (think like a std::any but limited to a set of types):
template<typename... Ts> // One of these types will be held
struct type_eraser_thing
{
void* obj; // pointer to actual thing
std::function<void*(void*,void*)> move_constr;
std::function<void*(void*,void const*)> copy_constr;
// Plus other goodies not shown
std::size_t size;
template<typename T>
type_eraser_thing(T const& other)
{
// static_assert to make sure T is in Ts...
// Get the memory
obj = malloc(sizeof(T));
obj = new (obj) T(other);
size = sizeof(T);
// Save the move_constructor
move_constr = [](void* dest, void* src){
return new (dest) T(std::move(*reinterpret_cast<T*>(src)));
};
}
// Other stuff (copy constructor, etc)
//
// The real problem the move constructor:
type_eraser_thing(T&& other)
{
obj = malloc(other.size);
obj = other.move_constr(obj,other.obj);
obj.move_constr = other.move_constr;
other.obj = nullptr;
}
};
In the implementation of the move constructor, it doesn't make sense to have a call to a std::function (not really, but something similar) if the move constructor doesn't do anything, so I want to SFINAE it out if it doesn't do anything
The concept you seem to be looking for is:
template <typename T>
concept C = not std::is_trivially_move_constructible_v<T>;
Here's a demo.
If you don't have c++20, you can write this trait yourself, or just use the right hand side where needed, since it's pretty short.
Related
Let's say I have a large blob object that is stack allocated. I need to put that in a wrapper object but I want to avoid a copy. Should I just use std::move with a move constructor? What would be the easiest way to prove that it works?
struct Blob {
char blob[1024 * 1024]; // imagine something big here
};
template <typename T>
struct Foo {
Foo(T&& src) : data{src} {}
T data;
};
int main() {
Blob blob;
Foo foo{std::move(blob)}; // do not copy
// should not take twice the memory of a blob
}
In this case, Blob is plain old data. The compiler is free to optimize the variable Blob blob out of existence.
It is also free to make a million copies of it for no reason whatsoever. The standard does not constrain it.
There is an optimization called "static single assignment" that represents local object states as independent existence variables, which allows the compiler to get rid of a pile of nonsense copies or other state changes that don't matter. Sufficiently complex code, or reference/pointer leaks outside of the scope of optimization, block it.
So, in practice, just don't block the compiler from optimizing Blob blob's existence away.
That being said
Foo(T&& src) : data{src} {}
this should read
Foo(T&& src) : data{std::forward<T>(src)} {}
Also, you could do a
Foo<Blob&> foo(blob);
and have Foo store a reference to the Blob data. This changes the "value semantics" of Foo in nasty ways however.
Note that your implicit deduction guide is equally crazy, in that if you pass an lvalue you'll get a Foo wrapping a reference, but if you pass an rvalue you get a Foo wrapping a value.
If you want a hard guarantee, C++ doesn't provide that. C++ doesn't even guarantee that Blob blob; actually takes up space on the stack.
Going further, you can do this:
int main() {
Foo foo{[&]{
Blob blob;
return blob;
}()};
}
in this case, Blob blob's existence is elided into the return value, which in turn is passed to foo, then the lifetime of the return value ends at th end of the full-expression. Instead of a lambda, you can also use another function outside of main.
This makes it a bit easier for the compiler to work out that there is no point in a separate Blob object, but not be a huge amount.
If you want to make elision of the Blob blob directly into the Foo data be more guaranteed, add a Foo constructor that takes a Blob factory:
template <typename T>
struct Foo {
template<class U>
requires std::is_same_v< std::decay_t<U>, T >
Foo(U&& src) : data{std::forward<U>(src)} {}
template<class F>
requires std::is_invocable_r_v< T, F&& >
Foo(F&& f) : data(std::forward<F>(f)()) {}
T data;
};
template<class T>
requires !std::is_invocable_v< T&& >
Foo(T&&)->Foo<std::decay_t<T>>;
template<class F>
requires std::is_invocable_v< F&& >
Foo(F&&)->Foo<std::decay_t<std::invoke_result_t<F&&>>>;
int main() {
Foo foo{[&]{
Blob blob;
return blob;
}};
}
which is probably going way, way too far.
Either:
Keep reference to original object in wrapper and use it through this.
Use NRVO to avoid copying.
E.g.
struct Blob {
char blob[1024 * 1024]; // imagine something big here
};
template <typename T>
struct Foo {
template<typename = std::enable_if_t<std::is_default_constructible<T>::value>>
Foo(): data(){}
T data;
};
Foo<Blob> ProcessBlob(){
Foo<Blob> value{};
Blob& blob = value.data;
// Use `blob` here
return value; // NRVO would eliminate copying
}
void ProcessIn2Steps(){
Foo<Blob> wrapped = ProcessBlob();
// Use `wrapped` here
}
Also, if your really want to avoid copies, consider removing copy constructors of Foo:
template <typename T>
struct Foo {
template<typename = std::enable_if_t<std::is_default_constructible<T>::value>>
Foo(): data(){}
Foo(const Foo&) = delete;
Foo(Foo&&) = delete;
Foo& operator=(const Foo&) = delete;
Foo& operator=(Foo&&) = delete;
T data;
};
I have a question about allocate_unique from Boost. It looks like that resulting unique_ptrs are quite limited - they cannot be default constructed to nullptr without providing a deleter (even an invalid one), and also, move assignment does not work.
Luckily, move construction does work, so I was able to hack around not having move assignment by calling the destructor and move-constructing using placement new.
Is it a defect in Boost that alloc_deleter is not moveable, and thus disables move assignment of these unique_ptrs? Or am I misunderstanding something?
#include <memory>
#include <memory_resource>
#include <boost/smart_ptr/allocate_unique.hpp>
#include <iostream>
using Pma = std::pmr::polymorphic_allocator<std::byte>;
template<typename T> using pmr_deleter = boost::alloc_deleter<T, Pma>;
template<typename T> using pmr_unique_ptr = std::unique_ptr<T, pmr_deleter<T>>;
struct Vertex {
float x = 1;
float y = 2;
float z = 3;
};
int main() {
auto& res = *std::pmr::new_delete_resource();
pmr_deleter<Vertex> d(nullptr);
pmr_unique_ptr<Vertex> v_empty(nullptr, d); // will not default construct without deleter??
pmr_unique_ptr<Vertex> v = boost::allocate_unique<Vertex>(Pma(&res), Vertex{7,8,9});
// v_empty = std::move(v); // operator=(unique_ptr&&) gets deleted because `alloc_deleter` is not moveable!
// We can hack in a move like this:
v_empty.~pmr_unique_ptr<Vertex>();
new (&v_empty) pmr_unique_ptr<Vertex>(v.get(), v.get_deleter());
v.release();
std::cout << v_empty->x << "," << v_empty->y << "," << v_empty->z << std::endl;
return 0;
}
Polymorphic allocators are stateful, which means they cannot be default-constructed - because they wouldn't know about the memory resource they're supposed to work with.
This is not particular to PMR or unique pointers, it will also crop up when e.g. using Boost Interprocess allocators on a vector - you will always have to pass an initializer for the allocator.
Ifff you want a global/singleton memory resource, you can obviously declare a custom deleter that encodes that constant:
template <typename T> struct pmr_deleter : boost::alloc_deleter<T, Pma> {
pmr_deleter()
: boost::alloc_deleter<T, Pma>(std::pmr::new_delete_resource()) {}
};
This would allow the default constructor(s) to work:
pmr_unique_ptr<Vertex> v_empty; // FINE
pmr_unique_ptr<Vertex> v_empty(nullptr); // ALSO FINE
However it comes at the cost of no longer being type-compatible with the allocate_unique factory return type (alloc_deleter).
You can probably pave hack this, but I think it would probably be best to understand the situation before you decide whether that's worth it. (Hint: I don't think it is, because it is precisely the goal of PMR to type erase the allocator difference, trading in runtime state instead. If you go and move all state into the allocator again, you effectively made it a static allocator again, which is where we would have been without PMR anyways)
Other Notes
pmr_deleter<Vertex> d(nullptr);
Is ill-formed, as the argument may never be null. Both the compiler will warn about this at -Wnon-null, just as Asan/UBSan will:
/home/sehe/Projects/stackoverflow/test.cpp:18:34: runtime error: null pointer passed as argument 2, which is declared to never be null
Here is a wrapper I wrote around the specialization of std::unique_ptr<T, boost::alloc_deleter>. The unique pointer returned by boost::allocate_unique is implicitly convertible to the wrapper. The wrapper is default constructible, move-assignable and also has .get() return a raw pointer instead of a boost fancy pointer type (which requires an additional .ptr() to get a raw pointer).
The only downside is that you have to use the wrapper explicitly instead of e.g. auto with boost::allocate_unique.
using Pma = std::pmr::polymorphic_allocator<std::byte>;
template<typename T> using pmr_deleter = boost::alloc_deleter<T, Pma>;
template<typename T> class pmr_unique_ptr : public std::unique_ptr<T, pmr_deleter<T>> {
public:
using std::unique_ptr<T, pmr_deleter<T>>::unique_ptr;
T* get() const { return std::unique_ptr<T, pmr_deleter<T>>::get().ptr(); }
pmr_unique_ptr() : std::unique_ptr<T, pmr_deleter<T>>(nullptr, pmr_deleter<T>(std::pmr::null_memory_resource())) { }
pmr_unique_ptr(decltype(nullptr)) : pmr_unique_ptr() { }
template<typename P>
pmr_unique_ptr(std::unique_ptr<P, pmr_deleter<P>>&& p)
: pmr_unique_ptr(static_cast<T*>(p.get().ptr()), *reinterpret_cast<pmr_deleter<T>*>(&p.get_deleter())) {
p.release();
}
template<>
pmr_unique_ptr(std::unique_ptr<T, pmr_deleter<T>>&& p) : std::unique_ptr<T, pmr_deleter<T>>(std::move(p)) { };
pmr_unique_ptr(T* p, pmr_deleter<T> d) : std::unique_ptr<T, pmr_deleter<T>>(boost::detail::sp_alloc_ptr<T,T *>(1, p), d) { };
pmr_unique_ptr(const pmr_unique_ptr&) = delete;
pmr_unique_ptr(pmr_unique_ptr&& p) : std::unique_ptr<T, pmr_deleter<T>>(std::move(p)) { }
template<typename P> operator pmr_unique_ptr<P>() {
P* basep = static_cast<P*>(get());
pmr_deleter<P> d(*reinterpret_cast<pmr_deleter<P>*>(&this->get_deleter()));
this->release();
return {basep, std::move(d)};
}
pmr_unique_ptr& operator=(pmr_unique_ptr&& other) {
this->std::unique_ptr<T, pmr_deleter<T>>::~unique_ptr();
new (static_cast<std::unique_ptr<T, pmr_deleter<T>>*>(this)) std::unique_ptr<T, pmr_deleter<T>>(std::move(other));
return *this;
}
template<typename P> pmr_unique_ptr& operator=(std::unique_ptr<P, pmr_deleter<P>>&& p) {
return operator=(pmr_unique_ptr(pmr_unique_ptr<P>(std::move(p))));
}
};
Example which compiles:
#include <memory_resource>
#include <boost/smart_ptr/allocate_unique.hpp>
// ... the definitions from above
// ...
pmr_unique_ptr<int> p;
pmr_unique_ptr<int> p2 = nullptr;
p2 = boost::allocate_unique<int>(Pma(std::pmr::new_delete_resource()), 5);
p = std::move(p2);
int *rawp = p.get();
I need to create a simple template container, which can store any object of any type and could be used everywhere. So, I did something like this:
template <typename Type>
class Container {
public:
Container() : arraySize(10) { valueWrappers = new Type[arraySize];}
Container(const Container& other) { /* --- */}
~Container() { /* --- */}
Container& operator=(const Container& other) { /* --- */}
/* some functions */
private:
int arraySize;
Type* valueWrappers;
};
Now I have the problem - when I'm trying to create my container using as template a class without default constructor, the compilation error appears:
class MyClass {
public:
MyClass(int value) :v(value) { }
private:
int v;
};
int main() {
Container<MyClass> cont;
return 0;
}
C2512 'MyClass': no appropriate default constructor available
The problem is that I need to initialize the array of "Type" values with something, but I don't no what I need to use. I can't use NULL because, in this case, Container will work only with pointers. So, can somebody give an advice, how am I able to do it? Or, maybe, there is another way to solve this task?
Based on your requirements, I think you're going to have to use placement new. Since you haven't provided all the relevant code, I'm going to do what I can.
First, you're going to have to allocate raw memory instead of using new directly.
Container() : arraySize(10) { valueWrappers = reinterpret_cast<Type*>(::operator new(sizeof(Type) * arraySize)); }
Now when you put something in your Container, you'll have to construct it in place, using something like the following:
new (valueWrappers + index) Type(arguments to type);
In your destructor, you'll need to explicitly call the destructors on any object that you used placement new for.
valueWrappers[index]->~Type();
Lastly, release the memory using ::operator delete.
::operator delete(valueWrappers);
Please bear in mind that this is a very quick and dirty answer, and this code can be hard to debug and maintain. You're going to have to keep track of what indexes in valueWrapper have been initialized and which haven't during cleanup. If possible, I highly recommend using something akin to std::vector, which handles all this complexity for you.
One option is to not allocate the array in the default constructor, but initialise valueWrappers to null instead. Another option is to not have a default constructor in your template. Third option is to keep your class as-is and simply document that the template is default constructible only if the type argument is default constructible.
You can use std::optional to defer initialization, which is guaranteed to handle object lifetime correctly. Letting a default constructed container have 10 elements is also a questionable choice — a (count) constructor may be preferable.
template <typename Type>
class Container {
using elem_t = std::optional<Type>;
std::size_t count{};
std::unique_ptr<elem_t[]> elems{};
public:
Container() = default;
Container(std::size_t cnt)
: count{cnt}
, elems{std::make_unique<elem_t[]>(cnt)}
{
}
// for example
template <typename... Args>
void construct_at(std::size_t pos, Args&&... args)
{
assert(pos < count);
assert(!elems[pos]);
elems[pos].emplace(std::forward<Args>(args)...);
}
// ...
};
Note that I used std::unique_ptr to simplify memory management; a pointer will also be OK, though apparently more error-prone. Now you can traverse the container and construct the elements:
class MyClass {
public:
MyClass(int value) :v(value) { }
private:
int v;
};
int main()
{
Container<MyClass> cont(10);
for (std::size_t i = 0; i < 10; ++i) {
cont.construct_at(i, /* argument */);
}
}
I am implementing a type T. Although this is not a requirement, users of this type may benefit from move semantic, that is T(T&&) and T& operator=(T&&).
Since T contains std::function's as member data, I cannot implement move semantic with the noexcept guarantees, which would make T less useful for the user.
Also, for the above reason, my implementation cannot be as simple as: T(&&) noexcept = default and T& operator=(T&&) noexcept = default
The alternative would be to either offer the user the non-noexcept versions: T(&&) = default and T& operator=(T&&) = default; or implement my user defined noexcept move semantic in terms of std::function::swap() (which is guaranteed to be noexcept). In the latter case, I would unfortunately have to take care of all the other member data other than std::function's (ugly!).
So, there are three options:
disable move semantic at all
implement T(&&) = default and T& operator=(T&&) = default
implement my own T(&&) noexcept {/* lot of code */} and T& operator=(T&&) noexcept {/* lot of code */}
I know the question is rather subjective, but What would you opt for?
Assuming you really want the noexcept move, you can reduce the amount of boilerplate for option #3 by either:
grouping the default-noexcept-moveable members into a nested struct member or private base class, and write a move-ctor which simply moves that (one line for all of them), and then swaps the std::functions, or
writing a SwapMove template wrapper for storing a function in. It just needs to implement the move ctor and assignment operator using swap, and default everything else. OK, you'll also need to either expose the function member or forward the function call operator.
Why don't you try to put all your functions in a std::function inside a std::vector then swap the vector ?
vector has noexcept move constructor.
EDIT:
To fully expand the needed concepts, i cannot reply in comments.
For your situation (different function signatures) you will require type erasure and some dynamic casts.
Here's some code that uses all the stated concepts in a coment (vector and enum and others ).
Now you can keep a vector of your lambdas , regardless of signature.
class LambdaContainer
{
public:
struct GenericContainer {
virtual ~GenericContainer(){}
};
template <typename T>
struct SpecializedContainer : GenericContainer
{
SpecializedContainer(const T& t) : lambda(t){}
virtual ~SpecializedContainer(){}
T lambda;
};
private:
std::shared_ptr<GenericContainer> myLambda;
public:
template <typename T>
LambdaContainer(const T& aLambda) : myLambda(new SpecializedContainer<T>(aLambda)){}
std::shared_ptr<GenericContainer> getContainedLambda()
{
return myLambda;
}
};
enum eFunctions
{
FCT_INT=0,
FCT_FLOAT=1
};
...
int main()
{
int aa = 10;
float b = 3.0f;
std::function<void(int)> lambda1 = [aa](int arg)
{
printf("at this time b plus argument is %d\n ",aa+arg);
};
std::function<int (float, float )> lambda2 = [b] (float arg1, float arg2)
{ printf("calling the sum of floats %f , %f\n");
return (int)(arg1+arg2+b);};
std::vector<LambdaContainer> lambdaVector;
lambdaVector.push_back(LambdaContainer(lambda1));
lambdaVector.push_back(LambdaContainer(lambda2));
std::shared_ptr<LambdaContainer::GenericContainer> container = lambdaVector[FCT_INT].getContainedLambda();
LambdaContainer::SpecializedContainer<std::function<void(int)> >* ptr =
dynamic_cast<LambdaContainer::SpecializedContainer<std::function<void(int)> >*> (container.get());
if (ptr!=NULL)
{
std::function<void(int)> extractedLambda = ptr->lambda;
extractedLambda(5);
}
std::shared_ptr<LambdaContainer::GenericContainer> container2 = lambdaVector[FCT_FLOAT].getContainedLambda();
LambdaContainer::SpecializedContainer<std::function<int(float,float)> >* ptr2 =
dynamic_cast<LambdaContainer::SpecializedContainer<std::function<int(float,float)> >*> (container2.get());
if (ptr2!=NULL)
{
std::function<int(float,float)> extractedLambda = ptr2->lambda;
printf("the sum is %d\n",extractedLambda(3.0f,2.0f));
}
}
I have a class template S<T> and because the template parameter is sometimes hard write explicitly I also have a little helper function makeS(...) to deduce the template parameter.
Now the problem is that the constructor of S has a "side effect": it adds itself to a map which then will later be used to iterate over all instances of S. But this effectively makes S<T> s{...}; very different from auto s = makeS(...); (if RVO is not used).
Here is some code which hopefully shows what I'm trying to do. (Note: in the actual program, S has more than a single template parameter and all will be deduced in makeS)
#include <cassert>
#include <iostream>
#include <map>
#include <string>
#include <utility>
using namespace std;
struct Base
{
virtual ~Base() {}
virtual void f() const = 0;
};
static map<string, Base*> Map;
template <typename T>
struct S : Base
{
T Func;
Base* This;
S(string const& name, T func) : Func(std::move(func)), This(this)
{
//
// Automatically add this struct to Map...
//
Map.insert({name, this});
}
virtual void f() const override { Func(); }
};
template <typename T>
S<T> makeS(std::string const& name, T func)
{
return S<T>(name, std::move(func));
}
void func1()
{
std::cout << "func1\n";
}
int main()
{
struct Func2
{
void operator ()() const {
std::cout << "func2\n";
}
};
//
// This is not possible:
//
// S< ??? > s("s", [](){});
//
// This would be ok:
//
// auto F = [](){};
// S<decltype(F)> s("s", F);
//
auto s1 = makeS("s1", func1);
auto s2 = makeS("s2", Func2());
auto s3 = makeS("s3", [](){ std::cout << "func3\n"; });
//
// Manually adding s1,... to the Map is ok, but that's what
// I want to avoid...
//
// Map.insert({"s1", &s1});
// ...
//
assert(&s1 == s1.This);
assert(&s2 == s2.This);
assert(&s3 == s3.This);
for (auto&& I : Map)
{
I.second->f();
}
}
As I understand it, the map will only contain valid pointers if RVO is used in auto s1 = makeS(...) etc. and this is not guaranteed.
Is there a way to deduce the template parameters while at the same time avoiding the need to manually register s1,...?
Your basic problem is you failed to implement the rule of 3. If your destructor needs non-trivial behavior (and if you register yourself in the constructor, this is the case), you must either implement or block assignment and copy construct (and/or move-assign and move-construct).
In this case, we can implement a move-construct and block move-assign, and copy construct and copy assign are implicitly blocked.
First, add name to S. Then implement a move constructor.
template <typename T>
struct S : Base
{
std::string Name;
T Func;
Base* This; // ?? why ?? this looks both dangerous and useless at the same time!
S( S&& s ): Name(std::move(s.Name)), Func(std::move(s.Func)), This(this) {
s.clear(); // technically `move` need not clear.
map[Name] = this; // overwrite
}
S& operator=(S&& s) = delete; // or implement it
now your object is moveable, and when moved it updates the Map. ~S should, I assume, unregister from Map -- detect if your name is empty (and assert at construction you gain a non-empty name), and if it is don't unregister (as you where already moved from).
Now move-construct and elided-construct have the same semantics. RVO failure results in some inefficiency, but no logical failure. Plus, your type is now moveable, which tends to be really useful.
If you need to maintain object identity, use can use std::unique_ptr:
template <typename T>
std::unique_ptr<S<T>> makeS(std::string const& name, T func)
{
return { new S<T>(name, std::move(func)) };
}
Now moving the pointer from place to place won't move the object; the pointer kept in the map will stay valid.
My suggestions to improve your code:
1) Get rid of the side effect in the constructor. Create objects in a factory method only (makeS in your code; you can make it a static member function of S) and register the S objects in that method. To disable object creation in different ways make constructor(s) private.
2) Disable S objects copying/moving and handle the objects for example as shared_ptr/unique_ptr<S> only. When you disable copying/moving you avoid the problem when your map contains a pointer to invalid objects and now you don't need to rely on RVO.
3) Use std::function<void()> instead of T Func;. In that case your class don't need to be a template class (or it will have less template arguments). That will simplify your code.