Is this move and copy wrapper sound and complete? - c++

I just made a wrapper for move and copy operations to inject into code to see which is called in case of default implementations. I'm getting close to understanding when what is called but would like to double check at times.
I'm not sure if method 1 of using T::T; is better for the constructors than method 2 of forwarding the arguments like unique_ptr? I found it in this thread Forwarding all constructors in C++0x
In move constructor and assignment I use std::move to pass onto the super class. Should this be std::forward and if so, how? I get errors trying to use it.
#ifndef MOVECOPY_OBSERVER_H
#define MOVECOPY_OBSERVER_H
#include <iostream>
template<class T>
class MoveCopyObserver : public T {
public:
//1: Use "using" for constructors
//From https://stackoverflow.com/questions/3119929/forwarding-all-constructors-in-c0x
using T::T;
//2: Forward all args, unique_ptr style.
/*
template<typename... Args>
MoveCopyObserver(Args&&... args)
: T(std::forward<Args>(args)...)
{
};*/
// *************************************************************************
virtual ~MoveCopyObserver() = default;
// *************************************************************************
MoveCopyObserver(const MoveCopyObserver& other)
: T(other)
{
std::cout << "Copy constructor " << typeid(T).name() << std::endl;
}
// *************************************************************************
MoveCopyObserver(MoveCopyObserver && other)
: T(std::move(other)) //3: std::forward instead?
{
std::cout << "Move constructor " << typeid(T).name() << std::endl;
}
// *************************************************************************
MoveCopyObserver& operator=(const MoveCopyObserver& other)
{
T::operator=(other);
std::cout << "Copy assignment " << typeid(T).name() << std::endl;
return *this;
}
// *************************************************************************
MoveCopyObserver& operator=(MoveCopyObserver&& other)
{
T::operator=(std::move(other)); //3: std::forward instead?
std::cout << "Move assignment " << typeid(T).name() << std::endl;
return *this;
}
};
#endif //MOVECOPY_OBSERVER_H
The usage would be on the stack or through smart pointers, like so:
class A {
public:
A(std::string ss)
{
s = ss;
}
void f()
{
std::cout << "\"" << s << "\"" << std::endl;
}
private:
std::string s;
};
A a("Test instance");
a.foo();
MoveCopyObserver<A> b("Another instance");
b.foo();

Related

Capturing lambda in std::function results in extra copies

I am trying to write some code which allows me to call a function at some later time by storing the function call and its arguments in a lambda/std::function. Ideally, the arguments would only be copied ONCE (and moved oterhwise) but the smallest number of copies I can achieve seems to be 2.
//==============================================================================
// INCLUDES
//==============================================================================
#include <iostream>
#include <functional>
#include <memory>
//==============================================================================
// VARIABLES
//==============================================================================
static std::unique_ptr<std::function<void()>> queueFunction;
//==============================================================================
// CLASSES
//==============================================================================
class Test {
public:
Test(int a, int b = 20, int c = 30) : _a(a), _b(b), _c(c) {
std::cout << "Test: Constructor" << std::endl;
}
~Test() {
std::cout << "Test: Destructor" << std::endl;
}
Test(const Test& other) :
_a(other._a)
{
std::cout << "Test: Copy Constructor" << std::endl;
}
Test(Test&& other) :
_a(std::move(other._a))
{
std::cout << "Test: Move Constructor" << std::endl;
}
Test& operator=(const Test& other) {
if (this != &other) {
_a = other._a;
std::cout << "Test: Assignment Operator" << std::endl;
}
return *this;
}
Test& operator=(Test&& other) {
if (this != &other) {
_a = std::move(other._a);
std::cout << "Test: Move Assignment Operator" << std::endl;
}
return *this;
}
friend std::ostream& operator<<(std::ostream& os, const Test& v) {
os << "{a=" << v._a << "}";
return os;
}
private:
int _a;
int _b;
int _c;
};
//==============================================================================
// FUNCTIONS
//==============================================================================
void foo(const Test& t);
void _foo(const Test& t);
template <typename F>
void queue(F&& fn) {
std::cout << "queue()" << std::endl;
queueFunction = std::make_unique<std::function<void()>>(std::forward<F>(fn));
}
void dequeue() {
std::cout << "dequeue()" << std::endl;
if (queueFunction) {
(*queueFunction)();
}
queueFunction.reset();
}
void foo(const Test& t) {
std::cout << "foo()" << std::endl;
queue([t](){
_foo(t);
});
//Only a single copy of Test is made here
/*
[t](){
_foo(t);
}();
*/
}
void _foo(const Test& t) {
std::cout << "_foo()" << std::endl;
std::cout << "t=" << t << std::endl;
}
//==============================================================================
// MAIN
//==============================================================================
int main() {
std::cout << "main()" << std::endl;
Test test1(20);
foo(test1);
dequeue();
std::cout << "main() return" << std::endl;
return 0;
}
The output of the above code is:
main()
Test: Constructor
foo()
Test: Copy Constructor
queue()
Test: Copy Constructor
Test: Copy Constructor
Test: Destructor
Test: Destructor
dequeue()
_foo()
t={a=20}
Test: Destructor
main() return
Test: Destructor
Which makes no sense to me. Shouldn't the lambda capture the instance of Test once, then forward that lambda all the way to the new std::function thus causing a move?
If I modify my queue function as such I can at least get rid of once copy.
void queue(std::function<void()> fn) {
std::cout << "queue()" << std::endl;
queueFunction = std::make_unique<std::function<void()>>(std::move(fn));
}
Output:
main()
Test: Constructor
foo()
Test: Copy Constructor
Test: Copy Constructor
queue()
Test: Destructor
dequeue()
_foo()
t={a=20}
Test: Destructor
main() return
Test: Destructor
But I still cannot understand where the extra copy is coming from.
Can someone help to enlighten me?
AFAICT the problem is the const of the foo() argument. When you capture t inside foo(const Test& t), then the type of that capture inside the lambda is also const. Later when you forward the lambda, the lambda's move constructor will have no choice but copy, not move, the capture. You cannot move from const.
After changing foo to foo(Test& t) I get:
main()
Test: Constructor
foo()
Test: Copy Constructor
queue()
Test: Move Constructor
Test: Move Constructor
Test: Destructor
Test: Destructor
dequeue()
_foo()
t={a=20}
Test: Destructor
main() return
Test: Destructor
Alternative solution, mentioned in https://stackoverflow.com/a/31485150/85696, is to use capture in the form [t=t].
With move-capture and two other changes it is possible to eliminate this remaining copy constructor too:
- void foo(const Test& t) {
+ void foo(Test t) {
...
- queue([t](){
+ queue([t = std::move(t)](){
...
- foo(test1);
+ foo(std::move(test1));
main()
Test: Constructor
Test: Move Constructor
foo()
Test: Move Constructor
queue()
Test: Move Constructor
Test: Move Constructor
Test: Destructor
Test: Destructor
Test: Destructor
dequeue()
_foo()
t={a=20}
Test: Destructor
main() return
Test: Destructor

Copy assignment operator for variadic std::tuple

I have a variadic template with a variadic std::tuple as a member.
I declared the default assignment operator.
MSVC complains that the operator is deleted. I can still run the program.
It doesnt give the expected result.
So 3 Questions come to my mind:
Why is the default copy assignment operator not generated even if flagged as default?
Why can I run the programm still with the code posted?
How to declare a assignment operator for std::tuple<T...> template?
#include <string>
#include <iostream>
#include <tuple>
template<typename ...T>
class Variadic
{
public:
explicit Variadic(T... args)
:m_data{ std::move(args)... }
{
}
Variadic& operator=(const Variadic&) = default;
template<typename Type>
Type get_element() const
{
return std::get<Type>(m_data);
}
private:
std::tuple<T...> m_data{};
};
int main()
{
Variadic<int, std::string> tuple1{ 1, "a" };
Variadic<int, std::string> tuple2{ 2, "b" };
std::cout << tuple1.get_element<int>() << '\n'; // 1
std::cout << tuple1.get_element<std::string>() << '\n'; // a
std::cout << tuple2.get_element<int>() << '\n'; // 2
std::cout << tuple2.get_element<std::string>() << '\n'; // b
tuple2 = tuple1; // MSVC2017 gives warning here:
//function "Variadic<T...>::operator=(const Variadic<T...> &) [with T=<int, std::string>]"
//(declared at line 13) cannot be referenced -- it is a deleted function
// still it compiles ???
std::cin.get();
std::cout << tuple1.get_element<int>() << '\n'; // 1
std::cout << tuple1.get_element<std::string>() << '\n'; // a
std::cout << tuple2.get_element<int>() << '\n'; // expect 1 but 2 ?
std::cout << tuple2.get_element<std::string>() << '\n'; // expect b but a ?
}

What causes a move assignment operator to not be called?

I'm working on my own smart pointer and I ran into some weird problems. The move assignment operator was not being called. So I wrote a test class and was able to reproduce the issue. The move assignment operator is not called but a copy assignment occurs (even when there is no copy assignment operator).
This is my test class
#include <utility>
#include <iostream>
struct tag_t {};
constexpr tag_t tag {};
template <typename T>
struct Foo {
Foo() noexcept
: val{} {
std::cout << "Default construct\n";
}
template <typename U>
Foo(tag_t, const U &val) noexcept
: val{val} {
std::cout << "Construct " << val << '\n';
}
~Foo() noexcept {
std::cout << "Destruct " << val << '\n';
}
template <typename U>
Foo(Foo<U> &&other) noexcept
: val{std::exchange(other.val, U{})} {
std::cout << "Move construct " << val << '\n';
}
template <typename U>
Foo &operator=(Foo<U> &&other) noexcept {
std::cout << "Move assign " << other.val << '\n';
val = std::exchange(other.val, U{});
return *this;
}
T val;
};
These are the tests
int main() {
{
Foo<int> num;
std::cout << "Value " << num.val << '\n';
num = {tag, 5};
std::cout << "Value " << num.val << '\n';
}
std::cout << '\n';
{
Foo<int> num;
std::cout << "Value " << num.val << '\n';
num = Foo<int>{tag, 5};
std::cout << "Value " << num.val << '\n';
}
return 0;
}
After running the tests, I get these results
Default construct
Value 0
Construct 5
Destruct 5
Value 5
Destruct 5
Default construct
Value 0
Construct 5
Move assign 5
Destruct 0
Value 5
Destruct 5
What baffles me is the output of the first test. The move assignment operator is not called but a copy assignment takes place. This results in 5 being destroyed twice. Not ideal when you're trying to make a smart pointer!
I'm compiling with Apple Clang with optimizations disabled. Can someone explain my observations? Also, how do I ensure that the move assignment operator is called in the first test?
template <typename U>
Foo &operator=(Foo<U> &&other) noexcept;
this cannot be called by ={ }.
Instead, Foo& operator=(Foo&&)noexcept is called.
Template methods are never special member functions. Explicitly default, delete or implement them.

Use of placement-new operator and copy constructor instead of assignment operator

I found a problem while using 3rd party code which cannot be altered. I need to make a copy of object member. I can't do this strictly because one of inner members has private assignment operator. The only solution I found is tricky so I want to ask you if you see any red lights that can affect my program.
Here's the simplified code I'm dealing with (remember that I cannot change it!):
#include <iostream>
#include <algorithm>
class MBool
{
public:
MBool() {};
MBool(const MBool& arg) {}
private:
MBool& operator=(const MBool& arg);
};
class InnerContent {
private:
int* pBuffer;
public:
InnerContent() {
pBuffer = new int[20];
std::cout << "InnerContent()" << std::endl;
}
InnerContent(const InnerContent& otherInnerContent) {
pBuffer = new int[20];
std::copy(otherInnerContent.pBuffer, otherInnerContent.pBuffer + 20, pBuffer);
std::cout << "InnerContent(const InnerContent&)" << std::endl;
}
~InnerContent() {
std::cout << "~InnerContent()" << std::endl;
delete [] pBuffer;
pBuffer = nullptr;
}
virtual void someVirtualFunction() {}
};
class Content {
public:
InnerContent innerContent;
int someNumber;
MBool boolVar;
Content() {
std::cout << "Content()" << std::endl;
}
~Content() {
std::cout << "~Content()" << std::endl;
}
Content(const Content& otherContent) :
innerContent(otherContent.innerContent),
someNumber(otherContent.someNumber),
boolVar(otherContent.boolVar)
{
std::cout << "Content(const Content&)" << std::endl;
}
virtual void someVirtualFunction() {}
};
class A {
public:
Content content;
A() { std::cout << "A()" << std::endl; }
~A() { std::cout << "~A()" << std::endl; }
};
class B {
public:
Content content;
B() { std::cout << "B()" << std::endl; }
~B() { std::cout << "~B()" << std::endl; }
};
And here's what I'm about to do with it (only this code can be modified and extended):
void copyContent(Content& contentFrom, Content& contentTo) {
contentTo.~Content();
new (&contentTo) Content(contentFrom);
};
int main() {
A a;
B b;
// I wish to do this:
//b.content = a.content;
// but Content class has no operator= function implemented
// also I can't use generated assignment operator function because of MBool::operator= is private
// The only work-around I found is this:
std::cout << "--- Before copying" << std::endl;
copyContent(a.content, b.content);
std::cout << "--- After copying" << std::endl;
}
My solution is to call Content destructor manually to free any dynamically allocated memory in Content and its inner classes. Memory on the stack remains untouched so I can reuse it with placement-new operator that calls copy constructor that is present and does exactly what I need. When main function scope ends 'a' object is cleaned up properly.
Code output:
InnerContent()
Content()
A()
InnerContent()
Content()
B()
--- Before copying
~Content()
~InnerContent()
InnerContent(const InnerContent&)
Content(const Content&)
--- After copying
~B()
~Content()
~InnerContent()
~A()
~Content()
~InnerContent()
I don't want to make my own function that copies all the fields because this class can be updated in new version and there may be additional field that I will not copy and most probably no one will remember to fix it.
Question: Do you think this may cause any memory leaks or memory corruption? Do you see any problems that I didn't mention?
Basically the Idea should work. To protect yourself from forgetting to call the destructor, I think, you should wrap the whole think in a kind of smart pointer like class template. In this example it actually does not wrap a pointer, but the content object itself.
template <typename ContentType>
class content_wrapper {
private:
ContentType content_;
public:
content_wrapper() : content_ {} {};
content_wrapper(const content_wrapper& other) :
content_{other.content_} {};
content_wrapper& operator = (const content_wrapper& other) {
content_.~ContentType();
new (&content_) ContentType(other);
return *this;
}
ContentWrapper& operator * () {
return content_;
}
ContentWrapper* operator -> () {
return &content_;
}
};
now you can use it like that:
class A {
public:
content_wrapper<Content> content;
A() { std::cout << "A()" << std::endl; }
~A() { std::cout << "~A()" << std::endl; }
};
class B {
public:
content_wrapper<Content> content;
B() { std::cout << "B()" << std::endl; }
~B() { std::cout << "~B()" << std::endl; }
};
int main() {
A a;
B b;
b.content = a.content; // the wrapper will take care.
b.content->someVirtualFunction();
}
Easy to read and you can never forget the destructor call, whenever you want to assign a content object.

How to define a global variable template in C++?

Suppose you have to write a template library that operates on a client-supplied type. Also, suppose that this library really needs to access a global variable parameterized by the client-supplied type. How would you go about implementing this pattern?
#AnonymousCoward
this is derived from your solution. note the initialization/destruction patterns in this variant (read the output if you don't have it memorized already). you can use this to defer creation until access, and to destruct and free at termination (which may be useful for custom types):
#include <iostream>
#include <memory>
class t_custom {
public:
t_custom() {
std::cout << "custom ctor: " << __PRETTY_FUNCTION__ << "\n";
}
~t_custom() {
std::cout << "custom dtor: " << __PRETTY_FUNCTION__ << "\n";
}
};
template<typename T>
class Global {
public:
static T* Shared() {
std::cout << "enter: " << __PRETTY_FUNCTION__ << "\n";
static std::auto_ptr<T>pVar(new T);
std::cout << "access: " << __PRETTY_FUNCTION__ << ":\t\t";
return pVar.get();
}
private:
Global();
~Global();
Global(const Global& rhs);
Global& operator=(const Global& rhs);
};
template<typename T>
class Global_orig {
public:
static T* const pVar;
private:
Global_orig();
Global_orig(const Global_orig& rhs);
Global_orig& operator=(const Global_orig& rhs);
};
template<typename T>T* const Global_orig<T>::pVar(new T); // << oh no! global construction
int main(int argc, char* const argv[]) {
std::cout << ">> main: " << __PRETTY_FUNCTION__ << "\n\n";
std::cout << Global<float>::Shared() << "\n";
std::cout << Global<int>::Shared() << "\n";
std::cout << Global<t_custom>::Shared() << "\n";
std::cout << Global_orig<t_custom>::pVar << "\n";
std::cout << "\n<< main: " << __PRETTY_FUNCTION__ << "\n\n";
return 0;
}
it may also be a good idea for the client to supply a factory functor for you, rather than forcing them to use T's default initializer.
Here is the solution I use to emulate this behavior:
template <typename T> class Global {
public:
static T *pVar;
private:
Global() {}
Global(const Global& rhs) {}
void operator=(const Global& rhs) {}
};
template <typename T> T* Global<T>::pVar = new T;
It seems to do what I want for my particular application. Is there any problem that restricts its applicability?