#include <iostream>
static int i=0;
using namespace std;
class Movable
{
public:
Movable ():mId(++i){
cout<<"constructing it "<<mId<<endl;
};
Movable (const Movable&)=delete;
Movable (Movable&)=delete;
void operator=(Movable&)=delete;
void operator=(const Movable&)=delete;
Movable (const Movable&& aObject)
{
cout<<"Moving it constant "<<mId<<endl;
// mId=++i;
};
Movable (Movable&&aObject)
{
cout<<"Moving it "<<mId<<endl;
};
Movable &operator=( Movable&&aObject)
{
cout<<"Moving it assignment "<<mId<<endl;
return *this;
}
Movable &operator=(const Movable&&aObject)
{
cout<<"Moving it assignment constant "<<mId<<endl;
return *this;
}
~Movable ()
{
cout<<"destroying it "<<mId<<endl;
}
int getId() const {
return mId;
}
private:
int mId;
};
Movable&& CreatenNewMovable ()
{
Movable lM;
return std::move(lM);
}
int main() {
Movable a;
a=CreatenNewMovable();
return 0;
}
The output result of this code is
constructing it 1
constructing it 2
destroying it 2
Moving it assignment 1
destroying it 1
I'm a little bit confused how is it possible to destroy the temp object then move it to second. Is that an undefined behavior ? m I missing something about the move operation?
Yes, this function
Movable&& CreatenNewMovable ()
{
Movable lM;
return std::move(lM);
}
is broken.
An r-value reference is still a reference, in this case its a reference to a local stack object which is destroyed when the function terminates (before it is moved from). Instead you should just return it by value, it will still get moved out of and if there is copy-ellision then it will be efficient.
Look at this snippet:
Movable&& CreatenNewMovable ()
{
Movable lM;
return std::move(lM);
}
Actually this is Undefined Behaviour. There are 2 problems:
A function can return its value only by value (probably a reference value). So, you must replace Movable&& with Movable here.
Creating Movable lM; on the stack and referencing it outside the function is UB. When the function exits, the object no longer exists. Return it simply by value - in your case copy elision will be in effect.
Finally, a valid way is :
Movable CreatenNewMovable ()
{
Movable lM;
return lM;
// ..or..
// Even better to return like this(copy elision has less chances to fail)
// return Movable();
}
This will produce result you are waiting:
$ ./w
constructing it 1
constructing it 2
Moving it assignment 1
destroying it 2
destroying it 1
You can reduce even this job by removing empty object creation in your main:
int main() {
Movable a=CreatenNewMovable();
return 0;
}
/* Results:
$ ./w
constructing it 1
destroying it 1
*/
Related
In the following code I try to compare a vector of pointers via find_if and determine which contains a member a == 5 (in this case both of course, but it shows my case). However it doesn't compile.
#include <algorithm>
class obj
{
public:
int a = 5;
int b = 2;
};
int main()
{
obj A;
obj B;
std::vector<obj*> v = { &A, &B };
std::find_if(begin(v), end(v), [](const (obj*)& instance) { if((*instance)->a == 5) return true; });
}
From what I interpreted here, find_if provides the actual vector entry as parameter to the lambda function which is traditionally taken up via const ref. But how do I specify this for pointers, because I have pointers as vector entries?
(For the lengthy error message take this code to godbolt using gcc 11.1 but I guess it's down to me not knowing how to specify the lambda argument correctly)
You want to have const reference to pointer, not reference to const pointer:
[](obj* const& instance) { if(instance->a == 5) return true; return false; }
or with type alias for obj pointer, it is much clearer:
using PtrObj = obj*;
std::find_if(begin(v), end(v), [](const PtrObj& instance) { if(instance->a == 5) return true; return false; });
I have a class with a couple of fields, assignment c-tor and move c-tor:
class A{
std::vector<int> numbers;
int k;
public:
A(std::vector<int> &&numbers, const int k):
numbers(numbers), // fast
k(k)
{
// logic
}
A(const std::vector<int> &numbers, const int k):
A(std::move(std::vector<int>(numbers)), k) // copy-and-move vector
{
// empty
}
};
I want to keep logic in one c-tor and call it from others.
Also, I want to support fast move-semantics. And I have to explicitly copy-and-move arguments in the assignment c-tor.
Is there any way to avoid such nested construction and keep all advantages I've listed above?
You could delegate one constructor to the other:
struct A
{
A(const std::vector<int> & v) : A(std::vector<int>(v)) {}
A(std::vector<int> && v)
: v_(std::move(v))
{
// logic
}
// ...
};
The moving constructor is now as fast as it can be, and the copying constructor costs one more move than if you spell both constructors out. If you're willing to pay an extra move, though, you might as well just have a single constructor:
struct A
{
A(std::vector<int> v)
: v_(std::move(v))
{
// logic
}
};
The alternative is to put the common code into a function and call that from both constructors.
In my program, I have a bunch of objects of a custom class Position. The declaration of Position is as follows:
class Position {
public:
Position(int x, int y);
~Position();
Actor *getActor() { return actor.get(); };
void setActor(Actor *actor) { actor = std::move(actor); };
Actor *clearActor() { return actor.release(); };
int getX() { return x; };
int getY() { return y; };
private:
int x, y;
std::unique_ptr<Actor> actor;
};
I also have a class called Actor. Not every Position will have an Actor, and so the majority of the time the unique_ptr "actor" of a Position object should be empty (I'm using unique_ptrs to automatically clean up any Actor associated with a Position at runtime).
The Position constructor is as follows:
Position::Position(int x, int y)
{
this->x = x;
this->y = y;
actor.reset(nullptr);
}
However, I know that this isn't correctly setting the stored pointer to nullptr because when I try calling actor.get() inside Position::getActor(), I get an error as follows:
First-chance exception at 0x01096486 in ____.exe: 0xC0000005: Access violation reading location 0x00000008.
Is there a way to initialize a member unique_ptr to nullptr? I know I could get around this by adding a variable to the Actor class that defines whether or not the Actor is active, setting the unique_ptr to a new inactive Actor, and ignoring all inactive Actors, but I'd rather avoid this if possible.
Thanks!
Edit: I've added the code where I call getActor:
bool Grid::addActor(Actor *actor, int x, int y)
{
Position *destination = at(x, y);
if (!destination->getActor()) {
destination->setActor(actor);
actor->setPosition(x, y);
actor->setGrid(this);
return true;
}
else {
inactive_actors.emplace_back(actor);
return false;
}
}
Your error is here:
void setActor(Actor *actor) { actor = std::move(actor); };
You're assigning the result of std::move to the parameter actor. You probably meant to reset the member variable actor with the parameter actor:
void setActor(Actor *actor) { this->actor.reset(actor); };
As a side note, you can simply change your constructor to this:
Position::Position(int x, int y)
: x(x), y(y)
{
}
This will initialize the members x and y with the arguments, and default-initialize std::unique_ptr<Actor> actor to null.
You don't need to initialize the std::unique pointer to null. Just leave it as its default empty value in the constructor and only ever reset it to point to a non-null pointer.
I'm trying to use move semantics (just as an experiment).
Here is my code:
class MyClass {
public:
MyClass(size_t c): count(c) {
data = new int[count];
}
MyClass( MyClass&& src) : count(src.count) {
data = src.data;
src.count = 0;
src.data = nullptr;
}
void operator=( MyClass&& src) {
data = src.data;
count = src.count;
src.count = 0;
src.data = nullptr;
}
~MyClass() {
if (data != nullptr)
delete[] data;
}
int* get_data() const {
return data;
}
size_t get_count() const {
return count;
}
private:
MyClass(const MyClass& src) : count(src.count) {
data = new int[src.count];
memcpy(data, src.data, sizeof(int)*src.count);
}
void operator=(const MyClass& src) {
count = src.count;
data = new int[src.count];
memcpy(data, src.data, sizeof(int)*src.count);
}
int* data;
size_t count;
};
int main()
{
MyClass mc(150);
for (size_t i = 0; i < mc.get_count(); ++i)
mc.get_data()[i] = i;
MyClass &&mc2 = std::move(mc);
return 0;
}
But std::move does not move mc to mc2, it just copies (copyies pointer as it is). If I remove copy constructor compiler generates it for MyClass.
How can I force move semantics to be used? How can I make it to be used in such constructions:
MyClass mc2(mc); //Move, not copy
-or-
MyClass mc2 = mc; //Move, not copy
I tried to use a '&&' operator to explicitely mark rvalue, but, of cause, it didn't work.
You're declaring m2 as a reference, not as a value. So it still refers to what it was initialised with, namely m1. You wanted this:
MyClass mc2 = std::move(mc);
Live example
As for the second part - there is no way to force a construct like these:
MyClass mc2(mc); //Move, not copy
//-or-
MyClass mc2 = mc; //Move, not copy
to move. If you want to move from an lvalue (and mc is indeed an lvalue), you have to use std::move (or another cast to rvalue) explicitly.
There is one thing you could do, but it would be a dirty hack, make the code unintuitive and be a great source for bugs. You could add an overload of the copy constructor (and copy assignment operator) taking a non-const reference, which would do the move. Basically something like std::auto_ptr used to do before it was rightfully deprecated. But it would never pass code review with me, for example. If you want to move, just std::move.
A few side notes:
Calling delete or delete[] on a null pointer is guaranteed to be a no-op, so you can safely drop the if from your destructor.
It's generally preferable to use std::copy instead of memcpy in C++ code, you don't have to worry about getting the sizeof right
You can force move semantics, if you delete the copy constructor and the assignment operator
MyClass(const MyClass& src)= delete;
void operator=(const MyClass& src) = delete;
in this case the provided move constructor or move assignment operator will be picked.
Rewrite your class a bit with some comments. Look over it, you might notice a few things you missed. Like:
in MyClass(size_t c) not checking for c != 0.
in void operator=(const MyClass& src) not delete[] data; (if exists) before reallocating.
And some other tiny details.Hope your compiler can handle this.
class MyClass {
private:
// initialize memebers directly
int* data = nullptr;
size_t count = 0;
public:
// default empty contructor
MyClass() = default;
// destructor
~MyClass() {
*this = nullptr; // use operator = (nullptr_t)
}
// allow nullptr construct
MyClass(nullptr_t):MyClass() {}
// allow nullptr assignment (for clearing)
MyClass& operator = (nullptr_t) {
if(data) {
delete[] data;
data = nullptr;
}
count = 0;
return *this;
}
// chain to default constructor, redundant in this case
MyClass(size_t c):MyClass() {
// maybe size_t is 0?
if(count = c) {
data = new int[count];
}
}
// chain to default constructor, redundant in this case
MyClass(MyClass&& src):MyClass() {
*this = std::move(src); // forward to move assignment
}
MyClass& operator=(MyClass&& src) {
// don't swap with self
if(&src != this) {
// it's better to swap and let src destroy when it feels like it.
// I always write move contructor and assignment to swap data.
// it's gonna be destroyed anyway, or not...
std::swap(src.data, data);
std::swap(src.count, count);
}
return *this;
}
MyClass(const MyClass& src):MyClass() {
*this = src; // forward to copy assignment
}
MyClass& operator = (const MyClass& src) {
// don't copy to self
if(&src != this) {
// delete first
if(data) {
delete[] data;
data = nullptr;
}
// now reallocate
if(count = src.count) {
data = new int[count];
memcpy(data, src.data, sizeof(int)* count);
}
}
return *this;
}
// easy way to use the object in a if(object) to test if it has content
explicit operator bool() const {
return data && count;
}
// same as above but made for if(!object) to test if empty
bool operator !() const {
return !data || !count;
}
public:
int* get_data() const {
return data;
}
size_t get_count() const {
return count;
}
// add more custom methods
};
Now to move you do this:
MyClass object1; // default construct
MyClass object1(5); // construct with capacity
MyClass object2(object1); // copy constructor
MyClass object3(std::move(object1)); // move constructor
object2 = object1; // copy assignment
object3 = std::move(object1); // move constructor
std::swap(object2, object3); // swap the two
object2 = nullptr; // to empty it
if(object1); // bool cast
The v8::ResourceConstraints class is defined as follows:
class V8EXPORT ResourceConstraints {
public:
ResourceConstraints();
int max_young_space_size() const { return max_young_space_size_; }
void set_max_young_space_size(int value) { max_young_space_size_ = value; }
int max_old_space_size() const { return max_old_space_size_; }
void set_max_old_space_size(int value) { max_old_space_size_ = value; }
int max_executable_size() { return max_executable_size_; }
void set_max_executable_size(int value) { max_executable_size_ = value; }
uint32_t* stack_limit() const { return stack_limit_; }
// Sets an address beyond which the VM's stack may not grow.
void set_stack_limit(uint32_t* value) { stack_limit_ = value; }
private:
int max_young_space_size_;
int max_old_space_size_;
int max_executable_size_;
uint32_t* stack_limit_;
};
Can someone tell me what young_space_size, old_space_size, and max_executable_size are? What are their units, how are they related, etc.? There doesn't seem to be much documentation.
Also, how does one use the stack_limit property? For example, if I want my V8 isolate to use no more than 1MB of stack space, how would I calculate a pointer value for stack_limit?
v8/test/cctest/test-api.cc uses this function to calculate the limit:
// Uses the address of a local variable to determine the stack top now.
// Given a size, returns an address that is that far from the current
// top of stack.
static uint32_t* ComputeStackLimit(uint32_t size) {
uint32_t* answer = &size - (size / sizeof(size));
// If the size is very large and the stack is very near the bottom of
// memory then the calculation above may wrap around and give an address
// that is above the (downwards-growing) stack. In that case we return
// a very low address.
if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
return answer;
}