I have a class that stores some data and also a member that needs to modify some of the parent class data. Consider the following simplified example:
#include <iostream>
#include <vector>
#include <string>
struct Modifier {
std::vector<std::string> &stuff;
Modifier(std::vector<std::string> &ref) : stuff(ref) {}
void DoIt() {
std::cout << "stuff.size = " << stuff.size() << '\n';
}
};
struct Container {
std::vector<std::string> stuff;
Modifier modifier;
std::vector<std::string> BuildStuff(int n) {
return std::vector<std::string>{"foo", std::to_string(n)};
}
Container(int n) : stuff(BuildStuff(n)), modifier(stuff) {}
};
int main()
{
std::vector<Container> containers;
containers.emplace_back(5);
containers.emplace_back(42);
containers[0].modifier.DoIt();
containers[1].modifier.DoIt();
return 0;
}
When I run this, one of the emplaced instances correctly reports size 2, but the other one reports size 0. I assume there's some undefined behaviour happening due to emplacing, but I cannot pinpoint what is the root cause.
Also, is there a more elegant way to represent this scenario?
Live example: http://coliru.stacked-crooked.com/a/e68ae9bf2b7e6b75
When you do the second emplace_back, the vector may undergo a reallocation operation: in order to grow, it allocates a new memory block and moves the objects from the old to the new, and frees the old memory block.
Your Modifier object generates a dangling reference when moved: the target object's reference refers to the same object that the old reference did.
To fix this you could add a move-constructor to Container, and either add or delete the copy-constructor. The Modifier has to be initialized to refer to the Container it is a member of; but the default copy- and move-constructors will initialize the Modifier to refer to the source being copy/move'd from.
For example:
Container(Container&& o) : stuff(std::move(o.stuff)), modifier(stuff) {}
Container(Container const& o) : stuff(o.stuff), modifier(stuff) {}
Related
This simple code:
#include <iostream>
#include <vector>
struct my_struct
{
int m_a;
my_struct(int a) : m_a(a) { std::cout << "normal const " << m_a << std::endl; }
my_struct(const my_struct&& other) : m_a(other.m_a) { std::cout << "copy move " << other.m_a << std::endl; }
my_struct(const my_struct &other) : m_a(other.m_a) { std::cout << "copy const " << other.m_a << std::endl; }
};
class my_class
{
public:
my_class() {}
void append(my_struct &&m) { m_vec.push_back(m); }
private:
std::vector<my_struct> m_vec;
};
int main()
{
my_class m;
m.append(my_struct(5));
m.append(std::move(my_struct(6)));
}
produces this output:
normal const 5
copy const 5
normal const 6
copy const 6
copy const 5
The first call to append creates the object, and push_back creates a copy. Likewise, the second call to append creates the object, and push_back creates a copy. Now, a copy constructor of the first object is mysteriously called. Could someone explain me what happens? It looks like a strange side effect...
Now, a copy constructor of the first object is mysteriously called. Could someone explain me what happens? It looks like a strange side effect...
When you call push_back on std::vector, vector may need to grow it's size as stated in the cppreference:
If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.
You can use reserve before pushing anything to your vector. Try this:
class my_class
{
public:
my_class()
{
m_vec.reserve(10); // Use any number that you want.
}
void append(my_struct &&m) { m_vec.push_back(m); }
private:
std::vector<my_struct> m_vec;
};
Few other issues with your program:
You need to fix signature of your move constructor as move constructor requires rvalue reference (more specifically, xvalue or prvalue). It should like this:
my_struct(my_struct&& other) noexcept : m_a(other.m_a)
{
std::cout << "copy move " << other.m_a << std::endl;
}
noexcept is required as we need to inform C++ (specifically std::vector) that move constructor and destructor does not throw, using noexcept. Then the move constructor will be called when the vector grows. See this.
The method append should be:
void append(my_struct &&m)
{
m_vec.push_back(std::move(m));
}
To know why we need to use std::move on rvalue reference, see this Is an Rvalue Reference an Rvalue?. It says:
Things that are declared as rvalue reference can be lvalues or rvalues. The distinguishing criterion is: if it has a name, then it is an lvalue. Otherwise, it is an rvalue.
If you don't use std::move, then copy constructor would be called.
That's just how std::vector works!
When you call push_back(), the underlying array needs to grow to make room for the new element.
So internally, a new larger array is allocated and all the elements of the previous smaller array are copied into the freshly created array. This also comes with some overhead. Now, you can use some techniques to optimize away the copies.
If you have an idea of how large the array could grow, you can use the reserve() method to ensure that no resizing will occur upto that many locations.
vct.reserve(5)
This is will ensure that no resizing will occur until 5 elements.
Also, you can use the emplace_back() function to avoid an additional copy. It constructs the object in place. Simply pass the constructor parameters of the object to emplace_back()
The question holds for both stacks and queues, but I will just allude to a stack here for simplicity.
Assuming that we push non-const objects into std::stack, is it safe, when we're popping from the stack, to move the object at the top of the stack into a temporary variable before popping like in the following:
std::stack<std::string> st;
st.emplace("asdf");
auto popped = std::move(st.top());
st.pop();
Yes, it is safe, if you use the non-const version of the stack. (For a const version of the stack, you will most likely copy the object or get a compile error)
Since std::stack returns a non-const reference to an object, you are free to modify it. This includes moving out from the object.
Recall that moving from an object keeps it in a valid state (at least, if the class is implemented correctly). It does not destroy it. It is still there on the top of your stack. It just doesn't contain any definite value. The follow-up pop will call a proper destructor on it without a problem.
Note, that the moving-out is not allowed for std::priority_queue, because that kind of container actually cares about the contents. And - for that reason it just returns a const-reference, which cannot be used to move things out from it.
In response to Iamanon's observation that std::move can be perfomed on a const reference. In fact you can do that. Usually it is not useful though and it will usually reduce to a copy, instead of move. Consider the following example:
#include <iostream>
#include <string>
#include <stack>
class Foo {
public:
Foo() {
std::cout << "created\n";
}
~Foo() {
std::cout << "destroyed " << value << "\n";
}
Foo(const Foo& other) : value(other.value) {
std::cout << "copied\n";
}
Foo(Foo&& other) : value(other.value) {
other.value++;
std::cout << "moved\n";
}
Foo(const Foo&& other) : value(other.value) {
std::cout << "const-moved\n";
}
int value = 0;
};
int main()
{
std::stack<Foo> st;
st.emplace();
const std::stack<Foo>& cst = st;
auto popped = std::move(cst.top());
st.pop();
}
If you run the above, a const-moved version will be used. However, as you implement your const-move constructor you will realize that you cannot really do much better than your regular copy constructor. That is because other remain immutable. For example, you cannot take ownership of anything other holds, and reset it within other.
And if you remove the const-move constructor, the compiler will use the regular copy constructor.
If the copy-constructor is deleted, and only move-constructor is provided - then the compiler will throw an error at you.
I have a class "foo" which contains a member vector which holds elements of type "foo". This class has a method called "make", which creates "foo" objects and appends them to the vector. I also provide a method for navigating the "foo" object and it's "foo" vector elements called "get".
I would like to re-assign what "this" refers to on any "foo" object to point to a foo object within it's vector. I would like to give the code this functionality as a way to more efficiently navigate and keep track of foo objects without having to bind references to specific "foo" members. I am attempting to do this through a method called "setAsNode" which reassigns what "*this" is.
Here's some example code I mocked up which I believe gets my point across:
struct foo{
foo(const std::string &r):s(r){}
foo& make(const std::string &r){children.push_back(test(r)); children.back().originalNode = originalNode; return children.back();}
foo& setAsNode(){*originalNode = *this; return *originalNode;}
foo& get(int i){return children.at(i);}
private:
std::vector<foo> children;
std::string s = "someData";
foo *originalNode = this;
};
and a practical example of how this would function:
foo f1("test1");
f1.make("test2").make("test3");//pushes a new foo element back to the vector in f1 and pushes a new foo element back to it's vector
f1.get(0).get(0);//refers to the deepest nested object we just made above, cumbersome to type especially if the nesting is deep
f1.get(0).get(0).setAsNode();//this is where the error occurs, the desired effect is to make f1 the same object as denoted by f1.get(0).get(0);
foo& f2 = f1.get(0).get(0);//f2 would be equivalent to what I want the above code to reset f1 to be (or at least how I'd like it to act)
I realize I'm probably implementing some very bad programming practices such as using references instead of pointers for returning "foo" objects, but I honestly do not know how to correctly structure a program such as this, or how a best practice version of this program would look/work. Bonus points for whoever can show me the "right" way of doing things.
Back to the real question though: how would I make something like this, specifically the "setAsNode" method, actually work? Also, why doesn't the code in my example work? Note, it compiles fine, just crashes upon running.
The c++ way (and arguably only correct way) is to separate concerns.
A foo is not (or should not be) a foo-finder. It should do foo-things, not foo-navigation things.
Make a new class to act as the cursor or iterator of your foo.
Here is a slightly expanded version, in which the foo_cursor remembers its journey through the foo stack. Probably overkill for your problem but it demonstrates the principle of separating foo-navigation logic from foo-implementation logic.
The more you do this, the easier your programs will be to write, debug and maintain.
#include <utility>
#include <string>
#include <vector>
#include <stack>
#include <stdexcept>
#include <iostream>
struct foo{
foo(const std::string &r)
: children()
, s(r)
{}
foo& make(const std::string &r)
{
children.emplace_back(r);
return children.back();
}
foo& get(int i)
{
return children.at(i);
}
void print() const {
std::cout << s << std::endl;
}
private:
std::vector<foo> children;
std::string s = "someData";
};
struct foo_cursor
{
foo_cursor(foo& f)
: current_(std::addressof(f))
{}
foo_cursor& down(int i)
{
history_.push(current_);
current_ = std::addressof(current_->get(i));
return *this;
}
foo_cursor& up() {
if (history_.empty()) {
throw std::logic_error("went up too far");
}
else {
current_ = history_.top();
history_.pop();
}
return *this;
}
foo* operator->() const {
return current_;
}
private:
foo* current_;
std::stack<foo*> history_;
};
int main()
{
foo f("a");
f.make("b").make("c");
auto fc = foo_cursor(f);
fc.down(0).down(0)->print();
fc.up()->print();
fc.up()->print();
}
expected output:
c
b
a
In your example, the call to foo.get(0).get(0).setAsNode() will attempt to copy the value of foo.get(0).get(0) to foo. In the process, foo.children will be assigned a new value, causing the vector to clear it's previous elements leading to the destruction of foo.get(0).get(0). This means that this has been destroyed and that the pointer can't be used. However, this is happening during an assignment operation which us currently using this. To solve this, you must insure that the value being copied persists long enough to be copied. The intuitive solution might be to copy the value to assign before assigning it.
foo& setAsNode() {
auto this_copy = *this;
*originalNode = std::move(this_copy);
return *originalNode;
}
This will work, you still have to be careful never to use this after the assignment to *originalNode. Another solution would be to take control of originalNode's children vector before preforming the assignment. In this version this remains valid until the method returns but if the following assignment throws an exception your tree will be left in an invalid state.
foo& setAsNode() {
auto original_vect = std::move(originalNode->children);
*originalNode = *this;
return *originalNode;
}
All in all, I would be wary of a design that calls for objects to commit suicide. It implies object controls their own ownership or that ownership responsibilities are otherwise cyclical.
I am trying to experiment with std::variant. I am storing an std::variant as a member of a class. In the below code, things work fine if the variant is stored by value, but does not work (for the vector case, and for custom objects too) if the variant is stored by reference. Why is that?
#include <variant>
#include <vector>
#include <iostream>
template<typename T>
using VectorOrSimple = std::variant<T, std::vector<T>>;
struct Print {
void operator()(int v) { std::cout << "type = int, value = " << v << "\n"; }
void operator()(std::vector<int> v) const { std::cout << "type = vector<int>, size = " << v.size() << "\n"; }
};
class A {
public:
explicit A(const VectorOrSimple<int>& arg) : member(arg) {
print();
}
inline void print() const {
visit(Print{}, member);
}
private:
const VectorOrSimple<int> member; // const VectorOrSimple<int>& member; => does not work
};
int main() {
int simple = 1;
A a1(simple);
a1.print();
std::vector<int> vector(3, 1);
A a2(vector);
a2.print();
}
See http://melpon.org/wandbox/permlink/vhnkAnZhqgoYxU1H for a working version, and http://melpon.org/wandbox/permlink/T5RCx0ImTLi4gk5e for a crashing version with error : "terminate called after throwing an instance of 'std::bad_variant_access'
what(): Unexpected index"
Strangely, when writing a boost::variant version of the code with the member stored as a reference, it works as expected (prints vector size = 3 twice) with gcc7.0 (see here http://melpon.org/wandbox/permlink/eW3Bs1InG383vp6M) and does not work (prints vector size = 3 in constructor and then vector size = 0 on the subsequent print() call, but no crash) with clang 4.0 (see here http://melpon.org/wandbox/permlink/2GRf2y8RproD7XDM).
This is quite confusing. Can someone explain what is going on?
Thanks.
It doesn't work because this statement A a1(simple); creates a temporary variant object!
You then proceed to bind said temporary to your const reference. But the temporary goes out of scope immediately after the construction of a1 is over, leaving you with a dangling reference. Creating a copy works, obviously, since it always involves working with a valid copy.
A possible solution (if the performance of always copying worries you) is to accept a variant object by-value, and then move it into your local copy, like so:
explicit A(VectorOrSimple<int> arg) : member(std::move(arg)) {
print();
}
This will allow your constructor to be called with either lvalues or rvalues. For lvalues your member will be initialized by moving a copy of the source variant, and for rvalues the contents of the source will just be moved (at most) twice.
Variants are objects. They contain one of a set of types, but they are not one of those types.
A reference to a variant is a reference to the variant object, not a reference to one of the contained types.
A variant of reference wrappers may be what you want:
template<class...Ts>
using variant_ref=std::variant<std::reference_wrapper<Ts>...>;
template<typename T>
using VectorOrSimple = std::variant<T, std::vector<T>>;
template<typename T>
using VectorOrSimpleRef = variant_ref<T, std::vector<T>>;
template<typename T>
using VectorOrSimpleConstRef = variant_ref<const T, const std::vector<T>>;
Now store VectorOfSimpleConstRef<int>. (Not const&). And take one in the constructor as well.
Also modify Print to take by const& to avoid needlessly copying that std::vector when printing.
To demonstrate my problem, consider this simple program that does not compile:
#include <boost/noncopyable.hpp>
#include <unordered_map>
class foo : boost::noncopyable { };
int main()
{
std::unordered_map<int, foo> m;
auto & element = m[0];
return 0;
}
Using the current version of boost (1.52), Visual Studio 2012 returns the error:
cannot access private member declared in class 'boost::noncopyable_::noncopyable.
The operator [] for std::unordered_map returns a reference to the element at the provided key, which at first glance seems like it should work -- I've asked for a reference to the element, not a copy of it.
My understanding of the problem is this (which might be wrong, as I haven't used C++ in a while). If the key is not found, unordered_map creates a new element and returns a reference to the new element. boost::noncopyable defines a (private) copy constructor but not a move constructor, and so a move constructor is not generated by the compiler. In its operator[], std::unordered_map makes use of std::move, but since boost::noncopyable doesn't define a move constructor, it falls back to the copy constructor. Since the copy constructor is private, the compilation fails.
What prompted this post is that I'm trying to create an unordered_map of boost::signal2::signal, which inherits from boost::noncopyable. Short of hacking the boost library, is there a simple workaround I can do? Wrapping the signal in a unique_ptr is an option, but it seems to me I might be doing something wrong here.
Update:
I may have posted too soon! It appears impossible to add a subclass of boost::noncopyable to unordered_map. Insert, operator[], and emplace all use either a copy constructor (which is private), or a move operation (which doesn't exist for boost::noncopyable). To me this seems a major limitation. Is it even possible to create an unordered_map that contains boost::noncopyable objects? I'm explicitly not trying to copy them -- I want them to spend their entire lifespan inside the unordered_map.
It's not impossible to use a subclass of boost::noncopyable in an unordered_map, you simply have to define a move constructor for you type. C++ does not create a default move constructor if you've made your own copy construct (which is what boost::noncopyable does). Also, if it did define default move constructor, it would try to call the parent's copy constructor which is private. So you must define a move constructor that doesn't try to call boost::noncopyable's copy constructor. For example this works fine:
#include <boost/noncopyable.hpp>
#include <unordered_map>
struct foo : public boost::noncopyable
{
foo() = default;
foo(foo&&) {}
};
int main()
{
std::unordered_map<int, foo> m;
auto & element = m[0];
return 0;
}
This likely isn't exactly what you're looking for, but I figured I'd toss it out there. The one thing to note is the second value of the returned pair from emplace(), which indicates the second call does not introduce a new member, nor copy over the exiting member.
Again, I don't know if this is closer to what you want, but worth a shot. I likely did something wrong, as I'm not overtly familiar with the C++11 standard library as others. Sorry about that if so.
Finally, please note this is not attempting to address the OP's request of using operator []() for insert+access. Rather, it attempts to simply get a boost::noncopyable derivation constructed into an unordered_map<>. To access you would likely need a combination of the below as well as an initial find() to determine if the tag exists initially.
Anyway...
#include <boost/noncopyable.hpp>
#include <iostream>
#include <unordered_map>
class Foo : public boost::noncopyable
{
public:
Foo(int value) : value(value) {};
void setValue(int value) { this->value = value; }
int getValue() const { return value; }
private:
int value;
};
int main(int argc, char *argv[])
{
typedef std::unordered_map<std::string, Foo> MyMap;
MyMap mymap;
// throw ("test".1) into the map
auto p = mymap.emplace("test", 1);
auto q = mymap.emplace("test", 2); // should not overwrite the first.
// dump content
cout << p.first->second.getValue() << '(' << p.second << ')' << ' '
<< q.first->second.getValue() << '(' << q.second << ')' << endl;
// modify through the second returned iterator/bool pair.
q.first->second.setValue(3);
// dump again, see if p was also updated.
cout << p.first->second.getValue() << '(' << p.second << ')' << ' '
<< q.first->second.getValue() << '(' << q.second << ')' << endl;
return 0;
}
Output
1(1) 1(0)
3(1) 3(0)