mutable object referred by std::any - c++

Is only the way to modify, not replace, an object stored as std::any is to declare changeable data mutable? E.g. to avoid creation and copy of class S instances:
#include <iostream>
#include <vector>
#include <any>
#include <string>
struct S {
mutable std::string str;
S(S&& arg) : str(std::move(arg.str)) { std::cout << ">> S moved" << std::endl; }
S(const S& arg) : str(arg.str) { std::cout << ">> S copied" << std::endl; }
S(const char *s) : str(s) { std::cout << ">> S created" << std::endl; }
S& operator= (const S& arg) { str = arg.str; return *this; }
S& operator= (S&& arg) { str = std::move(arg.str); return *this; }
virtual ~S() { std::cout << "<< S destroyed" << std::endl; }
};
int main() {
std::vector<std::any> container;
container.emplace_back(S("Test 1"));
std::any_cast<const S&>(container[0]).str = "Test 2";
for (const auto& a : container) {
std::cout << a.type().name() << ", "
<< std::any_cast<const S&>(a).str << std::endl;
}
}

You can any_cast with non-const reference:
std::any_cast<S&>(container[0]).str = "Test 2";
Demo
or
std::any a = 40;
std::any_cast<int&>(a) += 2;
std::cout << std::any_cast<int>(a) <<std::endl;
Demo

nope.
The issue is here.
std::any_cast<const S&>(container[0]).str = "Test 2";
you are trying to change constant data

Related

Move (or copy) capture variadic template arguments into lambda

I am attempting to figure out how to move (or just copy if a move is not available) variadic parameters into a lambda within a templated function.
I am testing this with a move-only class (see below) because this would be the "worst-case" that needs to work with my template.
class MoveOnlyTest {
public:
MoveOnlyTest(int a, int b = 20, int c = 30) : _a(a), _b(b), _c(c) {
std::cout << "MoveOnlyTest: Constructor" << std::endl;
}
~MoveOnlyTest() {
std::cout << "MoveOnlyTest: Destructor" << std::endl;
}
MoveOnlyTest(const MoveOnlyTest& other) = delete;
MoveOnlyTest(MoveOnlyTest&& other) :
_a(std::move(other._a)),
_b(std::move(other._b)),
_c(std::move(other._c))
{
std::cout << "MoveOnlyTest: Move Constructor" << std::endl;
other._a = 0;
other._b = 0;
other._c = 0;
}
MoveOnlyTest& operator=(const MoveOnlyTest& other) = delete;
MoveOnlyTest& operator=(MoveOnlyTest&& other) {
if (this != &other) {
_a = std::move(other._a);
_b = std::move(other._b);
_c = std::move(other._c);
other._a = 0;
other._b = 0;
other._c = 0;
std::cout << "MoveOnlyTest: Move Assignment Operator" << std::endl;
}
return *this;
}
friend std::ostream& operator<<(std::ostream& os, const MoveOnlyTest& v) {
os << "{a=" << v._a << "}";
return os;
}
private:
int _a;
int _b;
int _c;
};
And here is the test code I am attempting to get working:
void test6() {
std::cout << "--------------------" << std::endl;
std::cout << " TEST 6 " << std::endl;
std::cout << "--------------------" << std::endl;
MoveOnlyTest v(1, 2, 3);
test6_A(std::move(v));
}
void test6_A(MoveOnlyTest v) {
std::cout << "test6_A()" << std::endl;
test6_B(test6_C, v);
}
template <typename ... ARGSF, typename ... ARGS>
void test6_B(void(*fn)(ARGSF...), ARGS&&... args) {
std::cout << "test6_B()" << std::endl;
//What do I need to get args to be moved/copied into the lambda
auto lambda = [fn, args = ???]() mutable {
(*fn)( std::forward<ARGS>(args)... );
};
lambda();
}
void test6_C(MoveOnlyTest v) {
std::cout << "test6_C()" << std::endl;
std::cout << "v = " << v << std::endl;
}
I am trying to have the exact same behavior as below, only using a generic template so that I can create a lambda which captures and arguments, and calls any function with those arguments.
void test5() {
std::cout << "--------------------" << std::endl;
std::cout << " TEST 5 " << std::endl;
std::cout << "--------------------" << std::endl;
MoveOnlyTest v(1, 2, 3);
test5_A(std::move(v));
}
void test5_A(MoveOnlyTest v) {
std::cout << "test5_A()" << std::endl;
auto lambda = [v = std::move(v)]() mutable {
test5_B(std::move(v));
};
lambda();
}
void test5_B(MoveOnlyTest v) {
std::cout << "test5_B()" << std::endl;
std::cout << "v = " << v << std::endl;
}
To be clear, I don't want to perfectly capture the arguments as in c++ lambdas how to capture variadic parameter pack from the upper scope I want to move them if possible and, if not, copy them (the reason being is that I plan to store this lambda for later execution thus the variables in the stack will no longer be around if they are just captured by reference).
To be clear, I don't want to perfectly capture the arguments as in c++
lambdas how to capture variadic parameter pack from the upper scope I
want to move them if possible
Just using the same form:
auto lambda = [fn, ...args = std::move(args)]() mutable {
(*fn)(std::move(args)...);
};
In C++17, you could do:
auto lambda = [fn, args = std::tuple(std::move(args)...)]() mutable {
std::apply([fn](auto&&... args) { (*fn)( std::move(args)...); },
std::move(args));
};

Move Constructor invoked for a function, but NRVO expected in C++

I don't understand why a move constructor is being invoked during the main function in the code below, specifically the output is:
FString::FString(string one)
FString::FString(string two)
FString::Move Constructor
FString::Move Assign
COMPLETE
So the line I am concerned about is "FString::Move Constructor" - this implies to me that the move constructor is getting invoked in order to fulfill the return statement of the function GetStringTemp(), but from what I understood NRVO should mean that the move constructor should not be invoked. Am I misunderstanding the behaviour of NVRO? Thanks in advance
#include <iostream>
#include <string>
class FString
{
public:
FString(std::string newstring)
: _string(newstring)
{
std::cout << "FString::FString(string "+newstring+")" << std::endl;
}
FString(const FString& rhs)
{
std::cout << "FString::Copy Constructor" << std::endl;
}
FString(FString&& rhs)
{
std::cout << "FString::Move Constructor" << std::endl;
}
FString& operator=(const FString& rhs)
{
std::cout << "FString::Copy Assign" << std::endl;
return *this;
}
FString& operator=(FString&& rhs)
{
std::cout << "FString::Move Assign" << std::endl;
return *this;
}
void Print()
{
std::cout << "Printing: "+_string << std::endl;
}
private:
std::string _string;
};
FString GetTempString()
{
FString temp = FString("two"); // 2: Expected Constructor cout
return temp; // No expected constructor as NVRO assumed
}
int main()
{
FString myString = FString("one"); // 1: Expected Constructor cout
myString = GetTempString(); // 3: Expected Move Assignment cout
std::cout << "COMPLETE" << std::endl;
}

Is there a way to avoid calling constructor and destructor for perfect forwarding to a function?

I am trying to pass literal to a perfect forwarding setter, but this results in object construction, movement and destruction instead. I am looking for a more efficient way to do this.
struct TStruct {
TStruct(int va) : a(va) {
std::cout << "- TStruct(" << va << ")" << std::endl;
}
TStruct(const TStruct& other) :
a(other.a)
{
std::cout << "- TStruct(const TStruct& )" << std::endl;
}
TStruct(TStruct&& other) :
a(std::exchange(other.a, 0))
{
std::cout << "- TStruct(const TStruct&&)" << std::endl;
}
TStruct& operator=(const TStruct& rhs) {
std::cout << "- TStruct operator= const& " << std::endl;
// check for self-assignment
if(&rhs == this) return *this;
a = rhs.a;
return *this;
}
TStruct& operator=(TStruct&& rhs) {
std::cout << "- TStruct operator=&&" << std::endl;
// check for self-assignment
if(&rhs == this) return *this;
a = std::exchange(rhs.a, 0);
return *this;
}
~TStruct() {
std::cout << "~ TStruct() destructor with " << a << std::endl;
}
int a = 1;
};
struct TPerfectForward {
template<class T>
TPerfectForward(T&& tsv) : ts(std::forward<T>(tsv)) {}
template<class T>
void set(T&& tsv) { ts = std::forward<T>(tsv); }
TStruct ts;
};
std::cout << "TPerfectForward (5)" << std::endl;
TPerfectForward pf(5);
std::cout << "TPerfectForward set(4)" << std::endl;
pf.set(4);
This gives following results with gcc 7.4.0 on Ubuntu:
TPerfectForward (5);
- TStruct(5)
TPerfectForward set(4)
- TStruct(4)
- TStruct operator=&&
~ TStruct() destructor with 0
I would like these results better:
TPerfectForward (5)
- TStruct(5)
TPerfectForward set(4)
- TStruct(4)
Is there a way to avoid calling move operator and destructor when perfect forwarding to a function?

Eliding copy/move when taking members out of a temporary

I'd like to take out members of a temporary without unnecessary moving or copying.
Suppose I have:
class TP {
T _t1, _t2;
};
I'd like to get _t1, and _t2 from TP(). Is it possible without copying/moving members?
I've tried with tuples and trying to "forward" (I don't think it's possible) the members, but the best I could get was a move, or members dying immediately.
In the following playground using B::as_tuple2 ends up with members dying too soon, unless the result is bound to a non-ref type, then members are moved. B::as_tuple simply moves is safe with auto on client side.
I suppose this should be technically possible, since the temporary dies immediately, and the member do die while they could bound to variables on the calling site (Am I wrong?), and structured binding of a similar struct works as intended.
Is it possible to extend/pass life of the member onto an outside variable, or elide the move/copy? I need it with c++14 version, but I couldn't get it to work on c++17 either, so I am interested in both.
Playground:
#include <tuple>
#include <iostream>
using std::cout;
class Shawty {
/**
* Pronounced shouty.
**/
public:
Shawty() : _id(Shawty::id++) {cout << _id << " ctor\n"; }
Shawty(Shawty && s) : _id(Shawty::id++) { cout << _id << " moved from " << s._id << "\n"; }
Shawty(const Shawty & s) : _id(Shawty::id++) { cout << _id << " copied from " << s._id << "\n"; }
Shawty& operator=(Shawty && s) { cout << _id << " =moved from " << s._id << "\n"; return *this;}
Shawty& operator=(Shawty & s) { cout << _id << " =copied from " << s._id << "\n"; return *this;}
~Shawty() {cout << _id << " dtor\n"; }
int _id;
static int id;
};
int Shawty::id = 0;
class B {
public:
auto as_tuple() && {return std::make_tuple(std::move(_s1), std::move(_s2));}
auto as_tuple2() && {return std::forward_as_tuple(std::move(_s1), std::move(_s2));}
private:
Shawty _s1, _s2;
};
struct S {
Shawty _s1, _s2;
};
int main() {
std::cout << "----------\n";
auto [s1, s2] = B().as_tuple2();
std::cout << "---------\n";
auto tpl1 = B().as_tuple2();
std::cout << "----------\n";
std::tuple<Shawty, Shawty> tpl2 = B().as_tuple2();
std::cout << "----------\n";
std::cout << std::get<0>(tpl1)._id << '\n';
std::cout << std::get<1>(tpl1)._id << '\n';
std::cout << std::get<0>(tpl2)._id << '\n';
std::cout << std::get<1>(tpl2)._id << '\n';
std::cout << s1._id << '\n';
std::cout << s2._id << '\n';
std::cout << "--struct--\n";
auto [s3, s4] = S{};
std::cout << s3._id << '\n';
std::cout << s4._id << '\n';
std::cout << "----------\n";
return 0;
}
No. It is not possible to extend the lifetime of more than one member beyond the lifetime of the super object.
So, the only way to "get" members without copying is to keep the super object alive, and refer to them:
// member function
auto as_tuple3() & {
return std::make_tuple(std::ref(_s1), std::ref(_s2));
}
// usage
B b;
auto [s1, s2] = b.as_tuple3();
An example of extending lifetime of the object by binding a reference to a single member. Note that this requires the member to be accessible from where the reference is bound (not the case in your example, where the member is private):
auto&& s1 = B{}._s1;
Add support for structured binding to your B type.
class B {
public:
template<std::size_t I, class Self,
std::enable_if_t< std::is_same_v<B, std::decay_t<Self>>, bool> = true
>
friend constexpr decltype(auto) get(Self&& self) {
if constexpr(I==0)
{
using R = decltype(std::forward<Self>(self)._s1)&&;
return (R)std::forward<Self>(self)._s1;
}
else if constexpr(I==1)
{
using R = decltype(std::forward<Self>(self)._s2)&&;
return (R)std::forward<Self>(self)._s2;
}
}
private:
Shawty _s1, _s2;
};
namespace std {
template<>
struct tuple_size<::B>:std::integral_constant<std::size_t, 2> {};
template<std::size_t N>
struct tuple_element<N, ::B>{using type=Shawty;};
}
Test code:
int main() {
std::cout << "----------\n";
{
auto&& [s1, s2] = B();
}
}
output:
----------
0 ctor
1 ctor
1 dtor
0 dtor
Live example.
This is the best I can do. Note that s1 and s2 are references into a lifetime-extended version of B.

std::map::clear and elements' destructors

Does destructor get called on std::map elements when std::map::clear is used?
I tried to debug for std::map<string,string> but could not see std::string destructor getting invoked. Can any one please help my understanding?
Documentation states it gets called, but I could not notice it.
Documentation is right, it does get called.
The destruction will be done by the method std::allocator<T>::deallocate(). Trace through that in your debugger.
http://www.cplusplus.com/reference/std/memory/allocator/
The destructor does get called. Here is an example to illustrate:
#include <iostream>
#include <map>
class A
{
public:
A() { std::cout << "Constructor " << this << std::endl; }
A(const A& other) { std::cout << "Copy Constructor " << this << std::endl; }
~A() { std::cout << "Destructor " << this <<std::endl; }
};
int main()
{
std::map<std::string, A> mp;
A a;
mp.insert(std::pair<std::string, A>("hello", a));
mp.clear();
std::cout << "Ending" << std::endl;
}
This will report an output similar to this:
Constructor 0xbf8ba47a
Copy Constructor 0xbf8ba484
Copy Constructor 0xbf8ba48c
Copy Constructor 0x950f034
Destructor 0xbf8ba48c
Destructor 0xbf8ba484
Destructor 0x950f034
Ending
Destructor 0xbf8ba47a
So, you can see that the destructors get called by the calling the clear function.
try with a std::map<A,B> where A and B are custom types that have a destructor in which you have set a breakpoint. You will see that it does get invoked, and exactly what scope this destruction happens at.
Here is a bit more of a complete test, building on Chris Mansley's code as I wanted to see the effect on values, ptrs and refs - and I wanted to see the difference
between clear and erase. No difference. In summary the destructor is only called
for value types, which you would expect. I just like to check my understanding 8)
#include <iostream>
#include <map>
class A
{
public:
std::string some_data;
A(std::string some_data) : some_data(some_data) {
std::cout << " A(" << some_data << ") #" << this << std::endl;
}
A(const A& other) {
some_data = other.some_data;
std::cout << " Copy A(" << other.some_data << ") #" << this << std::endl;
}
~A() {
std::cout << " Destruct ~A(" << some_data << ") #" << this << std::endl;
}
};
void clear_test_value (void)
{
std::cout << "clear_test_value() {" << std::endl;
std::map<std::string, A> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A>("key1", a));
mp.clear();
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void erase_test_value (void)
{
std::cout << "erase_test_value() {" << std::endl;
std::map<std::string, A> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A>("key2", a));
auto f = mp.find("key2");
if (f == mp.end()) {
std::cout << "failed to find element {" << std::endl;
return;
}
mp.erase(f);
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void clear_test_ptr (void)
{
std::cout << "clear_test_ptr() {" << std::endl;
std::map<std::string, A*> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A*>("key1", &a));
mp.clear();
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void erase_test_ptr (void)
{
std::cout << "erase_test() {" << std::endl;
std::map<std::string, A*> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A*>("key2", &a));
auto f = mp.find("key2");
if (f == mp.end()) {
std::cout << "failed to find element {" << std::endl;
return;
}
mp.erase(f);
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void clear_test_ref (void)
{
std::cout << "clear_test_ref() {" << std::endl;
std::map<std::string, A&> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A&>("key1", a));
mp.clear();
std::cout << "}" << std::endl;
std::cout << std::endl;
}
void erase_test_ref (void)
{
std::cout << "erase_test_ref() {" << std::endl;
std::map<std::string, A&> mp;
A a("A1 data");
mp.insert(std::pair<std::string, A&>("key2", a));
auto f = mp.find("key2");
if (f == mp.end()) {
std::cout << "failed to find element {" << std::endl;
return;
}
mp.erase(f);
std::cout << "}" << std::endl;
std::cout << std::endl;
}
int main ()
{
clear_test_value();
erase_test_value();
clear_test_ptr();
erase_test_ptr();
clear_test_ref();
erase_test_ref();
return (0);
}
Output:
clear_test_value() {
A(A1 data) #0x7ffee07389a0
Copy A(A1 data) #0x7ffee0738960
Copy A(A1 data) #0x7fe98fc029c8
Destruct ~A(A1 data) #0x7ffee0738960
Destruct ~A(A1 data) #0x7fe98fc029c8
}
Destruct ~A(A1 data) #0x7ffee07389a0
erase_test_value() {
A(A1 data) #0x7ffee07387f0
Copy A(A1 data) #0x7ffee07387b0
Copy A(A1 data) #0x7fe98fc029c8
Destruct ~A(A1 data) #0x7ffee07387b0
Destruct ~A(A1 data) #0x7fe98fc029c8
}
Destruct ~A(A1 data) #0x7ffee07387f0
clear_test_ptr() {
A(A1 data) #0x7ffee07389b0
}
Destruct ~A(A1 data) #0x7ffee07389b0
erase_test() {
A(A1 data) #0x7ffee0738800
}
Destruct ~A(A1 data) #0x7ffee0738800
clear_test_ref() {
A(A1 data) #0x7ffee07389b0
}
Destruct ~A(A1 data) #0x7ffee07389b0
erase_test_ref() {
A(A1 data) #0x7ffee0738800
}
Destruct ~A(A1 data) #0x7ffee0738800