Consider the following definition of Person:
struct Person
{
Person() { std::cout << "construct, "; }
Person(const Person&) { std::cout << "copy\n"; }
Person(Person&&) { std::cout << "move\n"; }
};
And 3 different functions to create a Person:
Person create1()
{
std::cout << "create1: ";
Person p1{};
return p1;
}
Person create2()
{
std::cout << "create2: ";
if constexpr (true)
{
Person p1{};
return p1;
}
else
{
Person p2{};
return p2;
}
}
Person create3()
{
std::cout << "create3: ";
if constexpr (true)
{
return Person{};
}
else
{
return Person{};
}
}
Finally, I call the create functions as follows:
int main()
{
Person p1 = create1();
Person p2 = create2();
Person p3 = create3();
return 0;
}
The output is:
create1: construct
create2: construct, move
create3: construct
What bothers me is the output of create2. If in create1 and create3, the move constructor is not called, why is it called in create2?
I am using GCC 12.0.0.
EDIT: Clang 13.0.0 does not call the move constructor.
I think it is an instance of NRVO in constant expression and cppreference says:
In constant expression and constant initialization, return value optimization (RVO) is guaranteed, however, named return value optimization (NRVO) is forbidden:
This is related to CWG 2278.
EDIT
I reconsidered :-) It is called from main(), so it can't be constant initialization. With actual constant initialization neither gcc nor clang do NRVO. In this example (see godbolt):
struct Person {
bool was_moved;
constexpr Person() : was_moved{false} { }
constexpr Person(const Person&) : was_moved{false} { }
constexpr Person(Person&&) : was_moved{true} { }
};
constexpr Person create() {
if (true) {
Person p1;
return p1;
}
else {
Person p2;
return p2;
}
}
constexpr Person p = create();
int main() {
return p.was_moved;
}
p.was_moved is 1.
As to why gcc doesn't do NRVO in create2(), one answer could be that it is not mandatory, as per the cppreference link earlier. Another could be that gcc implementation of NRVO is very "fragile". For example it works when only one named variable is involved:
Person create4() {
Person p{};
if (true) {
return p;
}
else {
return p;
}
}
but stops working when this whole thing is put in a sub-scope:
Person create5() {
{
Person p{};
if (true) {
return p;
}
else {
return p;
}
}
}
(see godbolt)
There is gcc bug from 2012 regarding both those issues: Bug 53637 - NRVO not applied where there are two different variables involved .
Related
struct Base
{
Base(int a_) : a(a_)
{
}
int a;
};
class Derived: public Base
{
public:
Derived(int i): Base(i)
{
}
Derived(const Derived && rhs)
: Base(std::move(rhs))
{
}
};
int main()
{
Derived d1(2);
Derived d2 = std::move(d1);
std::cout << d1.a << '\n';
}
Why the thing from which we just moved, that is, the thing that we just pilfered, is still accessible on subsequent lines of code? I mean d1.a.
I have some struct like this:
struct A { ... };
struct B { ... };
And I have a template like this:
template<typename struct_arg>
class X { ... }
Now I wanna create an array of arguments as struct like this:
args [2] { A, B };
for (args) {
X<args[i]> x;
}
Can I possible to create an array like this!?
Yes, you can do. std::variant is made for this usage and you can access such members of a variant with std::visit.
But if you do so, keep in mind, that each element of the array has an additional data member which has the type information and that each element has at minimum the size of the largest type you store. And also std::visit comes with a overhead, as a table for access the data member must be created. Typically done in compile time, but sometime g++ generates it in run time, which will decrease speed a lot!
struct A
{
void Do() { std::cout << "A" << std::endl; }
};
struct B
{
void Do() { std::cout << "B" << std::endl; }
};
int main()
{
std::array<std::variant< A,B >,2> arr{ A{}, B{}, B{}, A{} };
for ( auto& element: arr )
{
std::visit( []( auto& vari ) { vari.Do(); }, element );
}
}
Or if you like your encapsulation with an additional strucuture/class like given in your example:
struct A
{
void Do() { std::cout << "A" << std::endl; }
};
struct B
{
void Do() { std::cout << "B" << std::endl; }
};
template < typename struct_arg >
struct X: public struct_arg{};
int main()
{
std::array<std::variant< X<A>,X<B> >,2> arr{ X<A>{}, X<B>{} };
for ( auto& element: arr )
{
std::visit( []( auto& vari ) { vari.Do(); }, element );
}
}
After many trials I still do not understand how to properly take advantage of the move semantics in order to not copy the result of the operation and just use the pointer, or std::move, to "exchange" the data pointed to. This will be very usefull to speed-up more complicated functions like f(g(),h(i(l,m),n(),p(q()))
The objective is to have:
t3={2,4,6};
t1={}; // empty
While executing the code below the output is:
t3={2,4,6};
t1={1,2,3};
Code:
namespace MTensor {
typedef std::vector<double> Tensor1DType;
class Tensor1D {
private:
//std::shared_ptr<Tensor1DType> data = std::make_shared<Tensor1DType>();
Tensor1DType * data = new Tensor1DType;
public:
Tensor1D() {
};
Tensor1D(const Tensor1D& other) {
for(int i=0;i<other.data->size();i++) {
data->push_back(other.data->at(i));
}
}
Tensor1D(Tensor1D&& other) : data(std::move(other.data)) {
other.data = nullptr;
}
~Tensor1D() {
delete data;
};
int size() {
return data->size();
};
void insert(double value) {
data->push_back(value);
}
void insert(const std::initializer_list<double>& valuesList) {
for(auto value : valuesList) {
data->push_back(value);
}
}
double operator() (int i) {
if(i>data->size()) {
std::cout << "index must be within vector dimension" << std::endl;
exit(1);
}
return data->at(i);
}
Tensor1D& operator=(Tensor1D&& other) {
if (this == &other){
return *this;
}
data = other.data;
other.data = nullptr;
return *this;
}
void printTensor(Tensor1DType info) {
for(int i=0;i<info.size();i++) {
std::cout << info.at(i) << "," << std::endl;
}
}
void printTensor() {
for(int i=0;i<data->size();i++) {
std::cout << data->at(i) << "," << std::endl;
}
}
};
} // end of namespace MTensor
In file main.cpp:
MTensor::Tensor1D scalarProduct1D(MTensor::Tensor1D t1, double scalar) {
MTensor::Tensor1D tensor;
for(int i=0;i<t1.size();++i) {
tensor.insert(t1(i) * scalar);
}
//return std::move(tensor);
return tensor;
}
int main() {
MTensor::Tensor1D t1;
t1.insert({1,2,3});
std::cout << "t1:" << std::endl;
t1.printTensor();
MTensor::Tensor1D t3(scalarProduct1D(t1,2));
std::cout << "t3:" << std::endl;
t3.printTensor();
std::cout << "t1:" << std::endl;
t1.printTensor();
return 0;
}
Your use of new is a red flag, especially on a std::vector.
std::vectors support move semantics natively. They are a memory management class. Manual memory management of a memory management class is a BIG red flag.
Follow the rule of 0. =default your move constructor, move assignment, copy constructor, destructor and copy assignment. Remove the * from the vector. Don't allocate it. Replace data-> with data.
The second thing you should do is change:
MTensor::Tensor1D scalarProduct1D(MTensor::Tensor1D t1, double scalar) {
As it stands you take the first argument by value. That is great.
But once you take it by value, you should reuse it! Return t1 instead of creating a new temporary and returning it.
For that to be efficient, you will want to have a way to modify a tensor in-place.
void set(int i, double v) {
if(i>data->size()) {
std::cout << "index must be within vector dimension" << std::endl;
exit(1);
}
data.at(i) = v;
}
which gives us:
MTensor::Tensor1D scalarProduct1D(MTensor::Tensor1D t1, double scalar) {
for(int i=0;i<t1.size();++i) {
ts.set(i, t1(i) * scalar);
}
return t1; // implicitly moved
}
We are now getting close.
The final thing you have to do is this:
MTensor::Tensor1D t3(scalarProduct1D(std::move(t1),2));
to move the t1 into the scalarProduct1D.
A final problem with your code is that you use at and you check bounds. at's purpose is to check bounds. If you use at, don't check bounds (do so with a try/catch). If you check bounds, use [].
End result:
typedef std::vector<double> Tensor1DType;
class Tensor1D {
private:
//std::shared_ptr<Tensor1DType> data = std::make_shared<Tensor1DType>();
Tensor1DType data;
public:
Tensor1D() {};
Tensor1D(const Tensor1D& other)=default;
Tensor1D(Tensor1D&& other)=default;
~Tensor1D()=default;
Tensor1D& operator=(Tensor1D&& other)=default;
Tensor1D& operator=(Tensor1D const& other)=default;
Tensor1D(const std::initializer_list<double>& valuesList) {
insert(valuesList);
}
int size() const {
return data.size();
};
void insert(double value) {
data.push_back(value);
}
void insert(const std::initializer_list<double>& valuesList) {
data.insert( data.end(), valuesList.begin(), valuesList.end() );
}
double operator() (int i) const {
if(i>data.size()) {
std::cout << "index must be within vector dimension" << std::endl;
exit(1);
}
return data[i];
}
void set(int i, double v) {
if(i>data->size()) {
std::cout << "index must be within vector dimension" << std::endl;
exit(1);
}
data.at(i) = v;
}
static void printTensor(Tensor1DType const& info) {
for(double e : info) {
std::cout << e << "," << std::endl;
}
}
void printTensor() const {
printTensor(data);
}
};
MTensor::Tensor1D scalarProduct1D(MTensor::Tensor1D t1, double scalar) {
for(int i=0;i<t1.size();++i) {
t1.set(i, t1(i) * scalar);
}
return t1;
}
int main() {
MTensor::Tensor1D t1 = {1,2,3};
std::cout << "t1:" << std::endl;
t1.printTensor();
MTensor::Tensor1D t3(scalarProduct1D(std::move(t1),2));
std::cout << "t3:" << std::endl;
t3.printTensor();
std::cout << "t1:" << std::endl;
t1.printTensor();
return 0;
}
with a few other minor fixes (like using range-for, DRY, etc).
You need to move t1 when calling scalarProduct1D, otherwise you'll make a copy:
MTensor::Tensor1D t3(scalarProduct1D(std::move(t1),2));
You need to explicitly use std::move because t1 is an lvalue expression.
Note that you'll have to fix your printing functions to avoid dereferencing nullptr if you want accessing the moved-from object to be a valid operation. I instead suggest to avoid making method invocation on moved-from objects valid as it requires additional checks and doesn't follow the idea of "this object has been moved, now it's in an invalid state".
live wandbox example
I have code like this:
void function()
{
auto isOk=task(1);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(2);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(3);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(4);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(5);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(6);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(7);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(8);
if(!isOk)
{
return;
}
// more code here
auto isOk=task(9);
if(!isOk)
{
return;
}
}
It should be noted that I can not put them in a loop (My code is similar to this but not exactly this code)
The if block is very ugly and I may be bale to write it as follow:
#define TASK(x) {if(!task(x)) return;}
void function()
{
TASK(1);
// more code here
TASK(2);
// more code here
TASK(3);
// more code here
TASK(4);
// more code here
TASK(5);
// more code here
TASK(6);
// more code here
TASK(7);
// more code here
TASK(8);
// more code here
TASK(9);
}
My question is:
Is there any better way to do this when I am using C++11?
The problem with this code is:
I can not debug it easily.
The macro is not inside a namespace and maybe conflict with other macros.
Update 1
As most of the answer here tries to solve the problem in the specific code, when I am looking for the general solution, I am asking specifc questions related to this code:
1- Can I use lambda to mimic the macro?
2- Can I use a constexpr to mimic a macro?
3- Any other way to mimic a MACRO in a compiler friendly way (with the same result as a macro) so I can easily debug them?
void function() {
if (!task(1)) return;
// code here
if (!task(2)) return;
// more code here
if (!task(3)) return;
// more code here
}
This is small and tight and no ugly bulky blocks.
If task(1) is much larger, you can put return; on the next line indented.
Instead of using a plain return, you could choose to use exceptions instead, which not only leave the current function, but all functions until they find a catch block.
Something like this:
void tryTask(int i){
auto isOk=task(i);
if(!isOk)
{
throw std::runtime_error("Task failed: Nr. "+to_string(i));
}
}
function()
{
tryTask(1);
// more code here
tryTask(2);
// more code here
tryTask(3);
...
}
This however lets your function throw an exception instead of just returning if one of the tasks failed. If this is not what you want, surround it either inside the function with a try-catch block or call it from a second function like this:
void callfunction(){
try{
function();
} catch (std::exception& e) {
//do whatever happens if the function failed, or nothing
}
}
If you have control about the task() function, you might also decide to throw the exception directly inside this function instead of returning a bool.
If you want to make sure you only catch your own exceptions, write a small class for this taking only the information you need for handling the exception (if you don't need any, an empty class will do the job) and throw/catch an instance of your class instead.
Here's a quick and dirty approach with lambdas.
Assuming this is your task function:
#include <iostream>
/** Returns 0 on success; any other returned value is a failure */
int task(int arg)
{
std::cout << "Called task " << arg << std::endl;
return arg < 3 ? 0 : 1;
}
Invoke the tasks in a chain as follows:
#include <iostream>
int main()
{
int result = Chain::start()
.and_then([]() -> int {return task(1);})
.and_then([]() -> int {return task(2);})
.and_then([]() -> int {return task(3);})
.and_then([]() -> int {return task(4);})
.and_then([]() -> int {return task(5);})
.and_then([]() -> int {return task(6);})
.and_then([]() -> int {return task(7);})
.and_then([]() -> int {return task(8);})
.and_then([]() -> int {return task(9);})
.result();
std::cout << "Chain result: " << result << std::endl;
return result;
}
Because the task returns success only when called with an argument value less than 3, the invocation chain stops as expected after the 3rd step:
$ ./monad
Called task 1
Called task 2
Called task 3
Chain result: 1
This is the implementation of the Chain class:
class Chain
{
public:
const int kSuccess = 0;
Chain() {_result = kSuccess;}
static Chain start() { return Chain(); }
Chain& and_then(std::function<int()> nextfn) {
if(_result == 0) {
_result = nextfn();
}
return *this;
}
int result() { return _result; }
private:
int _result;
};
I know, it looks ugly and it's non-generic. But if this is the general direction you were thinking of, let me know and we can evolve it.
I would put code to execute btw calling task into a vector and then run a loop:
const size_t steps = 9;
using ops = std::function<void()>;
std::vector<ops> vops(steps);
steps[0] = [] { /* some code here to execute after task 0 */ };
...
for( size_t i = 0; i < steps; ++i ) {
if( !task(i) ) return;
if( vops[i] ) (vops[i])();
}
You can use an integer sequence.
// No task to call without an integer.
bool function(std::index_sequence<>) { return true; }
template<std::size_t I, std::size_t... S>
bool function(std::index_sequence<I, S...>) {
return [](){
auto isOk = task(I)
if (!isOk) return false;
// some code
return true;
// it will call function with the rest of the sequence only if the lambda return true.
}() && function(std::index_sequence<S...>{});
}
void function() {
// this call with a integer sequence from 0 to 9
function(std::make_index_sequence<10>{});
}
This code will expand just as if you'd write it by hands.
If the code between calls of task is different for each step, you can use a tuple.
auto afterTask = std::make_tuple(
[](){ std::cout << "after task 0" << std::endl; },
[](){ std::cout << "after task 1" << std::endl; },
[](){ std::cout << "after task 2" << std::endl; },
[](){ std::cout << "after task 3" << std::endl; },
[](){ std::cout << "after task 4" << std::endl; },
[](){ std::cout << "after task 5" << std::endl; },
[](){ std::cout << "after task 6" << std::endl; },
[](){ std::cout << "after task 7" << std::endl; },
[](){ std::cout << "after task 8" << std::endl; },
[](){ std::cout << "after task 9" << std::endl; }
);
And then change the definition of function with:
template<std::size_t I, std::size_t... S>
bool function(std::index_sequence<I, S...>) {
return task(I) &&
(static_cast<void>(std::get<I>(afterTask)()), true) &&
function(std::index_sequence<S...>{});
}
I've developed some concept code for a project that I will be working on shortly. The project lends itself to a state machine design and I think boost::statechart will do a good job. I hit a roadblock when I tried to use context() however. Here's a sample (I'm happy to put more code up, but I think this is the relevant part):
struct Wait : fsm::simple_state< Wait, Active > {
typedef mpl::list<fsm::transition< UnderflowEvent, Exec> > reactions;
public:
Wait()
: m_wait_op() {
std::cout << "entering wait state." << std::endl;
wait();
}
~Wait() { std::cout << "exiting wait state." << std::endl; }
private:
default_wait m_wait_op;
fsm::result wait() {
if(context<Active>().underflow_condition()) {
m_wait_op();
return transit<Wait>();
}
else if(context<Active>().overflow_condition()) {
return transit<Exec>();
}
else {
// undefined - keep waiting
}
}
};
The state Active has methods called "[over|under]flow_condition" which just return true at this point. Problems with my design aside, I am getting the following assertion failure when I instantiate thusly:
int main(void) {
Throttler my_throttler;
my_throttler.initiate();
return 0;
}
and here's the assertion:
assertion "get_pointer( stt.pContext_
) != 0" failed
I looked this assertion up in file "/usr/include/boost/statechart/simple_state.hpp", line 689 (boost 1.45) and the comments say that it is there to prevent simple_state from using contexts. This puzzled me when I revisited the stopwatch example and saw that the example was doing the very thing I was trying to do. So I compiled it and this assertion is not violated by the stopwatch code unsurprisingly. Am I missing something? Maybe there's something elsewhere in the code that I missed? Here's the entire header (please remember it's concept code... I'm not releasing this into the wild until it's been thoroughly genericized):
#ifndef _THROTTLER_H_
#define _THROTTLER_H_
#include<queue>
#include<vector>
#include<ctime>
#include<boost/statechart/event.hpp>
#include<boost/statechart/transition.hpp>
#include<boost/statechart/state_machine.hpp>
#include<boost/statechart/simple_state.hpp>
#include<boost/mpl/list.hpp>
#include<iostream>
namespace mpl = boost::mpl;
namespace fsm = boost::statechart;
namespace {
unsigned int DEFAULT_WAIT_TIME(1000);
}
struct noop {
public:
noop() { m_priority = (1 << sizeof(int)); }
noop(unsigned int priority) { m_priority = priority; }
virtual ~noop() {}
bool operator()(void) {
return true;
}
friend bool operator<(noop a, noop b);
private:
unsigned int m_priority;
};
bool operator<(noop a, noop b) {
return a.m_priority < b.m_priority;
}
struct compare_noops {
bool operator()(noop a, noop b) {
}
};
struct default_wait {
void operator()(unsigned long msecs = DEFAULT_WAIT_TIME) {
std::clock_t endtime =
std::clock() + (msecs*1000*CLOCKS_PER_SEC);
while(clock() < endtime);
}
};
struct OverflowEvent : fsm::event< OverflowEvent > {};
struct UnderflowEvent : fsm::event< UnderflowEvent > {};
struct ResetEvent : fsm::event< ResetEvent > {};
struct Active;
struct Throttler : fsm::state_machine< Throttler, Active > {};
struct Wait;
struct Active : fsm::simple_state< Active, Throttler, Wait > {
public:
typedef mpl::list<fsm::transition< ResetEvent, Active> > reactions;
bool overflow_condition(void) { return true; }
bool underflow_condition(void) { return true; }
void queue_operation(noop op) {
m_operation_queue.push(op);
}
void perform_operation(void) {
noop op(m_operation_queue.top());
if(op())
m_operation_queue.pop();
else
throw;
}
private:
std::priority_queue<noop, std::vector<noop>, compare_noops > m_operation_queue;
private:
std::priority_queue<noop, std::vector<noop>, compare_noops > m_operation_queue;
};
struct Exec : fsm::simple_state< Exec, Active > {
typedef mpl::list<fsm::transition< OverflowEvent, Wait> > reactions;
Exec() { std::cout << "entering exec state." << std::endl; }
~Exec() { std::cout << "exiting exec state." << std::endl; }
};
struct Wait : fsm::simple_state< Wait, Active > {
typedef mpl::list<fsm::transition< UnderflowEvent, Exec> > reactions;
public:
Wait()
: m_wait_op() {
std::cout << "entering wait state." << std::endl;
wait();
}
~Wait() { std::cout << "exiting wait state." << std::endl; }
private:
default_wait m_wait_op;
fsm::result wait() {
if(context<Active>().underflow_condition()) {
m_wait_op();
return transit<Wait>();
}
else if(context<Active>().overflow_condition()) {
return transit<Exec>();
}
else {
// undefined - keep waiting
}
}
};
#endif
As you've noted in your comment, it's related to attempting to access the outer context from within the constructor, which is not allowed for a simple_state.
From simple_state.hpp:
// This assert fails when an attempt is made to access the state machine
// from a constructor of a state that is *not* a subtype of state<>.
// To correct this, derive from state<> instead of simple_state<>.
BOOST_ASSERT( get_pointer( pContext_ ) != 0 );
So you should be able to access the outer context from the constructor if you base your states on the state class (rather than a simple_state).
That said, I'm not sure what impacts or implications this may have for your states. If this question gets an answer it may be helpful to you as well (:
From what I understand, you'll need to change Wait to derive from state:
struct Wait : fsm::state< Wait, Active > {
and then change the Wait() constructor to something like
typedef fsm::state< Wait, Active > my_base;
Wait( my_context ctx ) : my_base( ctx )
// and any other pre-constructor initialisation...
The my_context type is defined (as protected) within state<>, and needs to be passed in from the derived class's constructor.