I have written a move constructor for a class in the following way:
class A
{
std::vector<double> m;
A(A&& other)
: m{other.m}
{
}
}
Is this the correct way to move other.m to m?
Should I be doing this instead?
A(A&& other)
: m{std::move(other.m)}
{
}
Or perhaps I should be doing something else entirely?
The second snippet is the correct way to move other.m since it's a lvalue that needs to be turned into r-value-reference for std::vector move constructor to kick in.
even though, in this very specific example, it will be enough to simply write
A(A&& rhs) = default;
the compiler will generate a constructor that moves each member of rhs to the corresponing member of *this.
p.s. you also probably meant to make the constructor public.
/******************************************************************************
Below program demonstrates how to use move constructor and move assignment operator
*******************************************************************************/
#include <iostream>
#include <algorithm>
#include <vector>
class MemoryBlock
{
public:
MemoryBlock()
{
this->id++;
std::cout << "Default Constructor"<<std::endl;
}
// Simple constructor that initializes the resource.
explicit MemoryBlock(size_t length)
: _length(length)
, _data(new int[length])
{
this->id++;
std::cout << "Constructor In MemoryBlock(size_t). length = and id ="
<< _length << "." <<id<< std::endl;
}
// Destructor.
~MemoryBlock()
{
this->id--;
std::cout << "Destructor In ~MemoryBlock(). length = and id ="
<< _length << "."<<id;
if (_data != nullptr)
{
std::cout << " Deleting resource.";
// Delete the resource.
delete[] _data;
}
std::cout << std::endl;
}
// Copy constructor.
MemoryBlock(const MemoryBlock& other)
: _length(other._length)
, _data(new int[other._length])
{
this->id++;
std::cout << " Copy Constructor MemoryBlock(const MemoryBlock&). length = and id ="
<< other._length << "." <<id<<"Copying resource." << std::endl;
std::copy(other._data, other._data + _length, _data);
}
// Copy assignment operator.
MemoryBlock& operator=(const MemoryBlock& other)
{
std::cout << "Assignment operator In operator=(const MemoryBlock&). length = "
<< other._length << ". Copying resource." << std::endl;
if (this != &other)
{
// Free the existing resource.
delete[] _data;
_length = other._length;
_data = new int[_length];
std::copy(other._data, other._data + _length, _data);
}
return *this;
}
// Retrieves the length of the data resource.
size_t Length() const
{
return _length;
}
//Move copy constructor
MemoryBlock(MemoryBlock&& other) noexcept
: _data(nullptr)
, _length(0)
{
std::cout << "Move Constructor In MemoryBlock(MemoryBlock&&). length = "
<< other._length << ". Moving resource." << std::endl;
// Copy the data pointer and its length from the
// source object.
_data = other._data;
_length = other._length;
// Release the data pointer from the source object so that
// the destructor does not free the memory multiple times.
other._data = nullptr;
other._length = 0;
}
// Move assignment operator.
MemoryBlock& operator=(MemoryBlock&& other) noexcept
{
std::cout << "Move assignment operator In operator=(MemoryBlock&&). length = "
<< other._length << "." << std::endl;
if (this != &other)
{
// Free the existing resource.
delete[] _data;
// Copy the data pointer and its length from the
// source object.
_data = other._data;
_length = other._length;
// Release the data pointer from the source object so that
// the destructor does not free the memory multiple times.
other._data = nullptr;
other._length = 0;
}
return *this;
}
private:
size_t _length; // The length of the resource.
int* _data; // The resource.
static int id;
};
int MemoryBlock::id=0;
int main()
{
std::vector<MemoryBlock> v1;
MemoryBlock m1(100);
MemoryBlock m2(100);
MemoryBlock m3(100);
v1.push_back(m1);
v1.push_back(m2);
v1.push_back(m3);
return 0;
}
Related
I am trying to create a basic application which is modeling "sticky notes" activity. This would contain functions to add notes and delete notes. Below is the code. In deleteNote function, I am finding the title in the vector of Notes which is given as an input argument using std::find method. The std::find API is throwing compilation errors. Below is the code.
#include <iostream>
#include <vector>
#include <utility>
#include <tuple>
#include <algorithm>
using InitializerTags = std::initializer_list<std::string>;
using TupleObject = std::tuple<std::string, std::string, std::string>;
class Note
{
public:
TupleObject m_tags;
Note(std::string title, std::string text, std::string tags){
std::cout<< "parameterized Constructor"<< std::endl;
m_tags = std::make_tuple(title, text, tags);
}
/*Note(const Note& rhs){
std:: cout << "copy constructor"<< std::endl;
m_tags = rhs.m_tags;
}*/
Note(Note&& rhs){
std::cout<< "move constructor"<< std::endl;
m_tags = rhs.m_tags;
}
Note& operator=(Note&& rhs){
std::cout << "move assignment"<< std::endl;
if(this != &rhs){
m_tags = rhs.m_tags;
}
return *this;
}
Note() = delete;
Note(const Note& rhs) = delete;
Note& operator=(const Note& rhs) = delete;
~Note(){
}
};
class Storyboard
{
private:
std::vector <Note> m_notes;
public:
/*Storyboard(){
m_notes.reserve(1);
}*/
void addNote(std::string title, std::string text, std::string tags)
{
std::cout << "inside addNote"<< std::endl;
m_notes.emplace_back(title, text, tags);
}
void deleteNote(std::string title)
{
for(auto& x: m_notes){
if(std::get<0>(x.m_tags) == title){
m_notes.erase(std::find(m_notes.begin(),m_notes.end(), x));
}
}
}
void print()
{
std::cout << "Inside print"<< std::endl;
for(auto& x : m_notes){
std::cout << std::get<0>(x.m_tags)<< " ";
std::cout << std::get<1>(x.m_tags)<< " ";
std::cout << std::get<2>(x.m_tags)<< " ";
std::cout << std::endl;
}
}
};
Below is the error.
In file included from /usr/include/c++/5/bits/stl_algobase.h:71:0,
from /usr/include/c++/5/bits/char_traits.h:39,
from /usr/include/c++/5/ios:40,
from /usr/include/c++/5/ostream:38,
from /usr/include/c++/5/iostream:39,
from StoryBoard.cpp:1:
/usr/include/c++/5/bits/predefined_ops.h: In instantiation of ‘bool __gnu_cxx::__ops::_Iter_equals_val<_Value>::operator()(_Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<Note*, std::vector >; _Value = const Note]’:
/usr/include/c++/5/bits/stl_algo.h:120:14: required from ‘_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Note*, std::vector >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val]’
/usr/include/c++/5/bits/stl_algo.h:161:23: required from ‘_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator<Note*, std::vector >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val]’
/usr/include/c++/5/bits/stl_algo.h:3790:28: required from ‘_IIter std::find(_IIter, _IIter, const _Tp&) [with _IIter = __gnu_cxx::__normal_iterator<Note*, std::vector >; _Tp = Note]’
StoryBoard.cpp:67:73: required from here
/usr/include/c++/5/bits/predefined_ops.h:194:17: error: no match for ‘operator==’ (operand types are ‘Note’ and ‘const Note’)
{ return *__it == _M_value; }
I checked the files in which the error occurred.
The problem has occurred with the signature of std::find which is
std::find(_IIter, _IIter, const _Tp&)
The 3rd input argument is being taken as const reference and this is being compared with non const reference in predefined_ops.h:194.
I am trying to understand what in my code led to this situation.
Also trying to figure out the fix.
Any help which would clear my understanding would be appreciated.
In
std::find(m_notes.begin(),m_notes.end(), x)
std::find algorithm tries to compare an element from m_notes with x, but you didn't provide operator== which does it, hence error message. Becuase you are erasing elements based on title, you can write:
class Note
{
public:
//...
// comparison operator as member function
bool operator == (const Note& theOther) const {
// compare titles
return std::get<0>(m_tags) == std::get<0>(theOther.m_tags);
}
//...
};
then the code compiles, but probably it will crash.
You are using range-based for loop which checks vector::end iterator but it may be invalidated when vector::erase is called. See how range-for is implemented and how end is used.
Now you are iterating over all elements in vector and if title matches to title you are calling find to find element to be removed. It is overkill, you can go over vector with iterator and when title is matched just call erase algorithm for the current iterator without re-iterating vector by find:
Rewrite deleteNote into something like this:
void deleteNote(std::string title)
{
for (auto it = m_notes.begin(); it != m_notes.end(); )
{
if(std::get<0>(it->m_tags) == title)
it = m_notes.erase(it); // returns the first element past the removed one
else
++it;
}
}
If you want to move rhs.m_tags; in move ctor and move assignment operator you need to cast rhs.m_tags to Rreference - m_tags = std::move(rhs.m_tags);.
I love to use method chaining to completely initialize objects and then store them in const variables. When analyzing the resulting code it turns out that this means the execution of many copy constructors. Therefore I have wondered whether C++ 11 move semantics might help optimizing method chaining.
Indeed I have been able to significantly speed up my code by adding overloads with ref qualifiers to my chain methods. Please consider this source code:
#include <chrono>
#include <iostream>
#include <string>
#undef DEBUGGING_OUTPUT
#undef ENABLE_MOVING
class Entity
{
public:
Entity() :
data(0.0), text("Standard Text")
{
#ifdef DEBUGGING_OUTPUT
std::cout << "Constructing entity." << std::endl;
#endif
}
Entity(const Entity& entity) :
data(entity.data), text(entity.text)
{
#ifdef DEBUGGING_OUTPUT
std::cout << "Copying entity." << std::endl;
#endif
}
Entity(Entity&& entity) :
data(entity.data), text(std::move(entity.text))
{
#ifdef DEBUGGING_OUTPUT
std::cout << "Moving entity." << std::endl;
#endif
}
~Entity()
{
#ifdef DEBUGGING_OUTPUT
std::cout << "Cleaning up entity." << std::endl;
#endif
}
double getData() const
{
return data;
}
const std::string& getText() const
{
return text;
}
void modify1()
{
data += 1.0;
text += " 1";
}
Entity getModified1() const &
{
#ifdef DEBUGGING_OUTPUT
std::cout << "Lvalue version of getModified1" << std::endl;
#endif
Entity newEntity = *this;
newEntity.modify1();
return newEntity;
}
#ifdef ENABLE_MOVING
Entity getModified1() &&
{
#ifdef DEBUGGING_OUTPUT
std::cout << "Rvalue version of getModified1" << std::endl;
#endif
modify1();
return std::move(*this);
}
#endif
void modify2()
{
data += 2.0;
text += " 2";
}
Entity getModified2() const &
{
#ifdef DEBUGGING_OUTPUT
std::cout << "Lvalue version of getModified2" << std::endl;
#endif
Entity newEntity = *this;
newEntity.modify2();
return newEntity;
}
#ifdef ENABLE_MOVING
Entity getModified2() &&
{
#ifdef DEBUGGING_OUTPUT
std::cout << "Rvalue version of getModified2" << std::endl;
#endif
modify2();
return std::move(*this);
}
#endif
private:
double data;
std::string text;
};
int main()
{
const int interationCount = 1000;
{
// Create a temporary entity, modify it and store it in a const variable
// by taking use of method chaining.
//
// This approach is elegant to write and read, but it is slower than the
// other approach.
const std::chrono::steady_clock::time_point startTimePoint =
std::chrono::steady_clock::now();
for (int i = 0; i < interationCount; ++i)
{
const Entity entity = Entity().getModified1().getModified1().getModified2().getModified2();
#ifdef DEBUGGING_OUTPUT
std::cout << "Entity has text " << entity.getText() << " and data "
<< entity.getData() << std::endl;
#endif
}
const std::chrono::steady_clock::time_point stopTimePoint =
std::chrono::steady_clock::now();
const std::chrono::duration<double> timeSpan = std::chrono::duration_cast<
std::chrono::duration<double>>(stopTimePoint - startTimePoint);
std::cout << "Method chaining has taken " << timeSpan.count() << " seconds."
<< std::endl;
}
{
// Create an entity and modify it without method chaining. It cannot be
// stored in a const variable.
//
// This approach is optimal from a performance point of view, but it is longish
// and renders usage of a const variable impossible even if the entity
// won't change after initialization.
const std::chrono::steady_clock::time_point startTimePoint =
std::chrono::steady_clock::now();
for (int i = 0; i < interationCount; ++i)
{
Entity entity;
entity.modify1();
entity.modify1();
entity.modify2();
entity.modify2();
#ifdef DEBUGGING_OUTPUT
std::cout << "Entity has text " << entity.getText() << " and data "
<< entity.getData() << std::endl;
#endif
}
const std::chrono::steady_clock::time_point stopTimePoint =
std::chrono::steady_clock::now();
const std::chrono::duration<double> timeSpan = std::chrono::duration_cast<
std::chrono::duration<double>>(stopTimePoint - startTimePoint);
std::cout << "Modification without method chaining has taken "
<< timeSpan.count() << " seconds." << std::endl;
}
return 0;
}
The version without method chaining is approximately 10 times faster here than the other one. As soon as I replace
#undef ENABLE_MOVING
by
#define ENABLE_MOVING
the version without method chaining remains only 1.5 times faster than the other one. So this is a great improvement.
Still I wonder whether I could optimize the code even more. When I switch to
#define DEBUGGING_OUTPUT
then I can see that there are new entities created for every call to getModified1() or getModified2(). The only advantage of move construction is that creation is cheaper. Is there a way to even prevent move construction and work on the original entity with method chaining?
With the help of Igor Tandetnik I guess that I can answer my question!
The modification methods have to be changed to return rvalue references:
#ifdef ENABLE_MOVING
Entity&& getModified1() &&
{
#ifdef DEBUGGING_OUTPUT
std::cout << "Rvalue version of getModified1" << std::endl;
#endif
modify1();
return std::move(*this);
}
#endif
#ifdef ENABLE_MOVING
Entity&& getModified2() &&
{
#ifdef DEBUGGING_OUTPUT
std::cout << "Rvalue version of getModified2" << std::endl;
#endif
modify2();
return std::move(*this);
}
#endif
and the initialization has to happen like this:
const Entity entity = std::move(Entity().getModified1().getModified1().getModified2().getModified2());
Then the method chaining code is almost as efficient as the other code. The difference is one call to the move constructor and one additional destructor call for the temporary instance which is negligible.
Thank you for your help!
I have implemented a custom container (same vein as std::vector) and I am trying to make it so that its 'push_back' function would use leverage on move semantics to avoid creating a copy of whatever is being pushed back - specially when the object to be pushed into the container is returned by an external function.
After reading quite a bit about move semantics and custom containers, I still can't find why my approach is still generating a copy instead of just moving the passed object into the container's inner dynamic array.
Here is a simplified version of my container looks like:
template<class T>
class Constructor
{
private:
size_t size = 0;
size_t cap = 0;
T *data = nullptr;
public:
Constructor()
{
cap = 1;
size = 0;
data = static_cast<T*>(malloc(cap * sizeof(T)));
}
~Constructor()
{ delete[] data; }
template<typename U>
void push_back(U &&value)
{
if (size + 1 >= cap)
{
size_t new_cap = (cap * 2);
T* new_data = static_cast<T*>(malloc(new_cap * sizeof(T)));
memmove(new_data, data, (size) * sizeof(T));
for (size_t i = 0; i<cap; i++)
{
data[i].~T();
}
delete[] data;
cap = new_cap;
data = new_data;
new(data + size) T(std::forward<U>(value));
}
else
{
new(data + size) T(std::forward<U>(value));
}
++size;
}
const T& operator[](const size_t index) const //access [] overloading
{
return data[index];
}
};
Here is a custom class that will print messages when its instances are created, copied or moved, in order to help debugging:
class MyClass
{
size_t id;
public:
MyClass(const size_t new_id)
{
id = new_id;
std::cout << "new instance with id " << id << std::endl;
}
MyClass(const MyClass &passedEntity)
{
id = passedEntity.id;
std::cout << "copied instance" << std::endl;
}
MyClass(MyClass &&passedEntity)
{
id = passedEntity.id;
std::cout << "moved instance" << std::endl;
}
void printID() const
{
std::cout << "this instance's id is " << id << std::endl;
}
};
And here is the external function:
MyClass &foo(MyClass &passed)
{
return passed;
}
Lastly, here is the main function that runs a test case using the above function and classes to show the problem:
int main()
{
MyClass a(33);
std::cout << std::endl;
std::cout << "Using my custom container: " << std::endl;
Constructor<MyClass> myContainer;
myContainer.push_back(foo(a));
myContainer[0].printID();
std::cout << std::endl;
std::cout << "Using dinamic array: " << std::endl;
MyClass *dinArray = static_cast<MyClass*>(malloc(1 * sizeof(MyClass)));
dinArray = new(dinArray + 1) MyClass(std::forward<MyClass>(foo(a)));
dinArray[0].printID();
std::cout << std::endl;
system("Pause");
return 0;
}
The output is:
new instance with id 33
Using my custom container:
copied instance
this instance's id is 33
Using dinamic array:
moved instance
this instance's id is 33
As it can be seen, if the instance of MyClass is put directly into a dynamic array, then just the move conmstructor is called and not the copy constructor. However, if I push_back the yClass instance into an instance of Container, a copy constructor is still being called.
Could someone help me understand what exactly am I doing wrong here? How could I make it so that elements are pushed into the container without generating a copy?
When you call this line
myContainer.push_back(foo(a));
L-value is passed into push_back method, and now read about using std::forward - http://www.cplusplus.com/reference/utility/forward/,
Returns an rvalue reference to arg if arg is not an lvalue reference.
If arg is an lvalue reference, the function returns arg without modifying its type.
and in your push_back you call
new(data + size) T(std::forward<U>(value));
but value was passed as L-value, and only constructor MyClass(const MyClass &passedEntity) can be invoked.
If you want a object to be moved, you can write
myContainer.push_back(std::move(a)); // cast to R-reference
EDIT
You should not use move in your push_back function, below is simple example.
Suppose you have class like this:
struct Foo {
int i;
Foo (int i = 0) : i(i) {
}
~Foo () {
}
Foo (const Foo& ) {
}
Foo& operator=(const Foo&) {
return *this;
}
Foo (Foo&& f)
{
i = f.i;
f.i = 0; // this is important
}
Foo& operator=(Foo&& f)
{
i = f.i;
f.i = 0; // this is important
return *this;
}
};
we have also 2 functions
template<class T>
void process1 (const T& ) {
cout << "process1" << endl;
}
template<class T>
void process (T&& obj) {
cout << "process2" << endl;
T newObj = forward<T>(obj);
}
and bars functions are counterparts of your push_back method.
template <typename T>
void bar1 (T&& value) {
process (move(value)); // you use move in your push_back method
}
template <typename T>
void bar2 (T&& value) {
process (forward<T>(value));
}
now we must consider 4 cases:
[1] pass L-value, version with forward
Foo f(20);
bar2 (f);
cout << (f.i) << endl; // 20
[2] pass R-value, version with forward
Foo f(20);
bar2 (move(f));
cout << (f.i) << endl; // 0, it is OK bacuse we wanted to move 'f' object
[3] pass R-value, version with move
Foo f(20);
bar1 (move(f));
cout << (f.i) << endl; // 0, ok, we wanted to move 'f' object
[4] pass L-value, version with move in your push_back method
Foo f(20);
bar1 (f);
cout << (f.i) << endl; // 0 !!! is it OK ? WRONG
in last case, we passed f as L-value, but this object was moved in bar1 function, for me this is strange behavior and is incorrect.
It is not safe to perform a memmove with objects in C++.
You can find more information here Will memcpy or memmove cause problems copying classes?
If this is C++11 onwards, then what you want to use is placement new and the move constructor. (you could probably just bin the placement new though unless you really want to keep allocating memory yourself)
If this is any other version of C++ then you'll have to just accept that that either you're going to have to copy the object (like the rest of the stl) or that your object will have to implement a function like void moveTo(T& other)
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
This is my header :
class my_router_client : public FIX8::my::mine_Router {
private:
mine_session_client& _session;
mutable std::vector<std::string> vSymbolList;
public:
my_router_client(mine_session_client& session) : _session(session) {}
virtual bool operator() (const FIX8::my::SecurityList *msg) const;
void sendToServer(FIX8::Message *);
void logout();
void itertool() const;
};
I am trying to save the data obtained from security list response to the vSymbolList vector. After handling security response I am trying to iterate through the vector by itertool method. But every time I end up with an empty vector. I tried printing the contents of the vector inside securitylist response function
virtual bool operator() (const FIX8::CX::SecurityList *msg) const;
and I am able to print the contents. Is it some kind of race condition inside threads?
this is the security list response handler
bool cx_router_client::operator() (const CX::SecurityList *msg) const
{
GroupBase *dad(msg->find_group< CX::SecurityList::NoRelatedSym >());
if (dad) {
for (size_t cnt(0); cnt < dad->size(); ++cnt) {
CX::Symbol symbol;
MessageBase *details(dad->get_element(cnt));
details->get(symbol);
string ss;
ss = symbol();
vSymbolList.push_back(ss);
// cout << "at :: :: " << vSymbolList[cnt] << endl;
}
cout << "no of symbol : " << vSymbolList.size() << endl;
hypersleep<h_seconds>(1);
}
return true;
}
This is the itertool method :
void my_router_client::itertool() const
{
cout << "symbol list vector size inside itertool:: " << vSymbolList.size() << endl;
stringstream ss;
ss << this_thread::get_id();
uint64_t id = stoull(ss.str());
cout << "Thread ID #### " << id << endl;
vector<string>::iterator it = this->vSymbolList.begin();
while (it != vSymbolList.end()) {
cout << *it << endl;
it++;
}
}
This is how I use the them in main :
int main()
{
const string conf_file("myfix_client.xml");
unique_ptr<ClientSessionBase> mc(new ClientSession<mine_session_client>(my::ctx(), conf_file, "DLD1"));
mc->start(false, next_send, next_receive, mc->session_ptr()->get_login_parameters()._davi());
hypersleep<h_seconds>(1);
my_router_client *test = new my_router_client(static_cast< mine_session_client& > (*mc->session_ptr()));
hypersleep<h_seconds>(1);
test->sendToServer(makeSecurityListRequest());
hypersleep<h_seconds>(1);
test->itertool();
while(1);
}