I have a rapidjson wrapper that does the following:
class ADocument
{
void setJson(const char *data) { m_D.parse(data); }
AData operator[](const char *key) const
{
const rapidjson::Value *value = rapidjson::Pointer(key).Get(m_D);
if(value)
return AData(value);
else
return AData(&m_D);
}
private:
rapidjson::Document m_D;
};
and the AData class like this:
class AData
{
public:
Adata(const rapidjson::Value *val) : m_Value(val) {}
operator QString() const { return m_Value.IsString() ? m_Value.GetString() : QString(); }
private:
const rapidjson::Value *m_Value;
};
And the whole thing is called like this:
ADocument doc;
doc.setJson("{\"Hello\":{\"Hello\":\"test\"}}");
QString str = doc["/Hello/Hello"];
when str becomes "test".
Now by debugging this code I found out that the AData object somehow shifts - the operator QString() gets called from an object in different memory location than the original AData object is constructed in the operator[] of ADocument. Regular constructor is called once. But it might be that copy-elision simply moved the same object around in memory.
However when I define one of rule-of-three/five methods such as a destructor in AData without changing anything else (and the destructor does nothing itself) then the operator QString() is called on the SAME OBJECT (same memory location) which got constructed in the operator[] of ADocument.
Even when I implemented all thinkable constructors and operators (move, copy, assign...) NONE of them is ever called but the result is the same - only one object is ever created.
What is going on here? I would like to understand it.
And further, how to change this implementation so that it is as performance and memory efficient as possible (=minimum copies etc.)? Or maybe I am really worrying about nothing here and what I am seeing is only some compiler optimization?
What is going on here? I would like to understand it.
You're experiencing copy elision.
When a unnamed temporary would be copied or moved into a variable of the same type, the compiler is allowed to construct the object directly in the variable and skip the copy or move operation.
Another situation where you may experience this is when you return a variable with automatic storage duration from a function.
Related
I would like to know how to use getters and setters for a member variable which takes a lot of memory. Usualy i would do as bellow:
class A
{
private:
BigObject object;
public:
BigObject getObject() const
{
return object;
}
void setObject(const BigObject& object)
{
this->object = object;
}
};
However this getter and setter i believe will copy the BigObject which i do not want. Is there a better way to do this?
I thought of doing it this way but i read on the internet that it's not a good idea because it can lead to a segmentation fault if used badly:
BigObject& getObject()
{
return object
}
(If you do not care about encapsulation in this case, meaning the A::object member should be modifiable by anyone without restriction, then look at SergeyA's answer).
Return by const reference in order to avoid copying and still maintain encapsulation (meaning the caller can't modify the member by mistake):
const BigObject& getObject() const
{
return object;
}
If the caller actually wants a copy, they can do so easily themselves.
If you want to prevent dangling references (the segfault you mentioned) when the getter is used on a temporary, you can only return a copy when the getter is actually called on a temporary:
BigObject getObject() const &&
{
return object;
}
const BigObject& getObject() const &
{
return object;
}
This will return a copy when calling getObject() on a temporary. Alternatively, you can completely prevent calling the getter on a temporary by deleting that particular overload:
BigObject getObject() const && = delete;
const BigObject& getObject() const &
{
return object;
}
Keep in mind that this is not a guaranteed safety net. It prevents some mistakes, but not all of them. The caller of the function should still be aware about object lifetimes.
You can also improve your setter, btw. Right now, it will always copy the object regardless how the caller passes the argument. You should take it by value instead and move it into the member:
void setObject(BigObject object)
{
this->object = std::move(object);
}
This requires that BigObject is movable though. If it's not, then this will be even worse than before.
Best solution: make code of your class exactly that:
struct A
{
BigObject object;
};
Explanation - avoid trivial setters and getters. If you find yourself putting those into your classes, expose the member directly and be done with it.
Do not ever listen to people who'd say "But what if in the future we add non-trivial logic"? I have seen more than a healthy dose of trivial setters and getters, been around for decades, and never replaced with something non-trivial.
The common practice is to:
class A
{
public:
// this method is const
const& BigObject getObject() const
{
return object;
}
// this method is not const
void setObject(const BigObject& object)
{
object = object;
}
private:
BigObject object;
};
If you need to get a read-only object - it's perfectly fine. Otherwise, consider changes in architecture.
An alternative would be to store a std::shared_ptr and return a std::shared_ptr or std::weak_ptr.
Instead of returning a copy of the member, you can return a reference to it. This way there is no need to copy the member.
I thought of doing it this way but i read on the internet that it's not a good idea because it can lead to a segmentation fault if used badly
The solution is to not use it badly.
Returning a reference to a member is fairly common pattern and not generally discouraged. Although, for types that are fast to copy, returning a copy is generally superior when there is no need to refer to the member itself.
There is a solution that avoids both copying and breakage of encapsulation: Use a shared pointer, and return a copy of that shared pointer from the getter. However, this approach has a runtime cost and requires dynamic allocation, so it is not ideal for all use cases.
In case of setter, you may use move assignment instead, which is more efficient than copy assignment for some types.
I found unexpected (at least for me) behavior.
class A
{
char _text[100];
char* _beg;
char* _end;
public:
explicit A(char* text, size_t tsize) : _beg(&text[0]), _end(&text[std::min(tsize, 99)])
{
memcpy(_text, text, std::min(tsize, 99));
*_end = '\0';
}
inline std::string get_text()
{
return std::move(std::string(_beg, _end));
}
};
After that somewhere in code I do that:
A* add_A(A&& a)
{
list_a.push_back(std::move(a));
return &(list_a.back());
}
std::list<A> list_a;
{
add_A(A("my_text", 7));
list_a.back().get_text(); //returns "my_text"
}
list_a.back().get_text(); //returns trash
As only I move this class (using std::move), and call get_text() of object that was moved, I get trash, as if after movement address of variable _text changed, and so _beg and _end points to nowhere.
Does address of variables really can be changes after std::move (I thought move don't really move object, it was invented for that)?
If it can be changed, what is usual pattern to handle it (to change pointers accordingly)?
If it can't be change, may that behavior happens because I try to move such object to std::list (and so there somehow happens copying, it changes address of variables and makes pointers point to wrong positions)?
Moving in C++ is just a specialized form of copy, where you modify the data in the object being moved from. That's how unique_ptr works; you copy the pointer from one unique_ptr object to the other, then set the original value to NULL.
When you move an object, you are creating a new object, one who gets its data from another object. The address of members don't "change"; it's simply not the same object.
Because you didn't write a copy/move constructor, that means the compiler will write one for you. And all they do is copy each element. So the newly moved-to object will have pointers that point to the old object.
An object that is about to be destroyed.
It's like moving into a house that happens to look identical to your old one. No matter how much it looks like your old house, it isn't. You still have to change your address, since it's a new house. So too must the addresses of _beg and _end be updated.
Now, you could create a move constructor/assignment operator (along with a copy constructor/assignment operator) to update your pointers. But quite frankly, that's just wallpapering over bad design. It's not a good idea to have pointers to subobjects within the same object if you can help it. Instead of begin/end pointers, just have an actual size:
class A
{
char _text[100];
size_t _size;
public:
explicit A(char* text, size_t tsize) : _size(tsize)
{
strncpy(_text, text, 100);
}
inline std::string get_text()
{
return std::string(_text, _size); //Explicit `move` call is unnecessary
}
};
This way, there is no need to store begin/end pointers. Those can be synthesized as needed.
std::move has no moving parts, it simply promotes the input parameter to an rvalue reference -- remember that inside the body of foo(T&& t) { ... } the use of t by name evaluates as an lvalue (reference to rvalue).
inline std::string get_text()
{
return std::move(std::string(_beg, _end));
}
Breaking this down:
std::string(_beg, _end);
creates an anonymous, temporary std::string object constructed from _beg to _end. This is an rvalue.
std::move(...);
forcibly promotes this to an rvalue reference and prevents the compiler from performing return-value optimization. What you want is
return std::string(_beg, _end);
See assembly code comparison
You probably also want to use
list_a.emplace_back(std::move(a));
Unfortunately, there are two flaws in this approach.
The simpler is that the term moving can be a bit misleading, it sounds very one way. But in practice it is often a two way swap: the two objects exchange properties so that when the temporary object goes out of scope it performs cleanup of whatever the other object previously owned:
struct S {
char* s_;
S(const char* s) : s_(strdup(s)) {}
~S() { release(); }
void release() { if (s_) free(s_); }
S(const S& s) : s_(strdup(s.s_)) {}
S(S&& s) : s_(s.s_) { s.s_ = nullptr; }
S& operator=(const S& s) { release(); s_ = strdup(s); return *this; }
S& operator=(S&& s) { std::swap(s_, s.s_); return *this; }
};
Note this line:
S& operator=(S&& s) { std::swap(s_, s.s_); return *this; }
When we write:
S s1("hello");
s1 = S("world");
the second line invokes the move-assignment operator. The pointer for the copy of hello is moved into the temporary, the temporary goes out of scope and is destroyed, the copy of "hello" is freed.
Doing this swap with your array of characters is significantly less efficient than a one-way copy would be:
struct S {
char s_[100];
S(const S& s) {
std::copy(std::begin(s.s_), std::end(s.s_), std::begin(s_));
}
S(S&& s) {
char t_[100];
std::copy(std::begin(s.s_), std::end(s.s_), std::begin(t_));
std::copy(std::begin(s_), std::end(s_), std::begin(s.s_));
std::copy(std::begin(t_), std::end(t_), std::end(s_));
}
};
You don't have to do this, the rvalue parameter only needs to be in a safe to destroy state, but the above is what the default move operators are going to do.
The disasterous part of your code is that the default move operator is naive.
struct S {
char text_[100];
char *beg_, *end_;
S() : beg_(text_), end_(text_ + 100) {}
};
Consider the following copy-construction:
S s(S());
What does s.beg_ point to?
Answer: it points to S().text_, not s.text_. You would need to write a copy constructor that copied the contents of text_ and then pointed its own beg_ and end_ to its own text_ rather than copying the source values.
The same problem occurs with the move operator: it will move the contents of text_ but it will also move the pointers, and have no clue that they are relative.
You'll either need to write copy/move constructors and assignment operators, or you could consider replacing beg_ and end_ with a single size_t size value.
But in either case, move is not your friend here: you're not transferring ownership or performing a shallow copy, all of your data is inside your object.
Does C++ provide a guarantee for the lifetime of a temporary variable that is created within a function call but not used as a parameter? Here's an example class:
class StringBuffer
{
public:
StringBuffer(std::string & str) : m_str(str)
{
m_buffer.push_back(0);
}
~StringBuffer()
{
m_str = &m_buffer[0];
}
char * Size(int maxlength)
{
m_buffer.resize(maxlength + 1, 0);
return &m_buffer[0];
}
private:
std::string & m_str;
std::vector<char> m_buffer;
};
And here's how you would use it:
// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);
std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
When will the destructor for the temporary StringBuffer object get called? Is it:
Before the call to GetString?
After GetString returns?
Compiler dependent?
I know that C++ guarantees that a local temporary variable will be valid as long as there's a reference to it - does this apply to parent objects when there's a reference to a member variable?
Thanks.
The destructor for that sort of temporaries is called at the end of the full-expression. That's the most outer expression which is not part of any other expression. That is in your case after the function returns and the value is evaluated. So, it will work all nice.
It's in fact what makes expression templates work: They can keep hold references to that sort of temporaries in an expression like
e = a + b * c / d
Because every temporary will last until the expression
x = y
Is evaluated completely. It's quite concisely described in 12.2 Temporary objects in the Standard.
litb's answer is accurate. The lifetime of the temporary object (also known as an rvalue) is tied to the expression and the destructor for the temporary object is called at the end of the full expression and when the destructor on StringBuffer is called, the destructor on m_buffer will also be called, but not the destructor on m_str since it is a reference.
Note that C++0x changes things just a little bit because it adds rvalue references and move semantics. Essentially by using an rvalue reference parameter (notated with &&) I can 'move' the rvalue into the function (instead of copying it) and the lifetime of the rvalue can be bound to the object it moves into, not the expression. There is a really good blog post from the MSVC team on that walks through this in great detail and I encourage folks to read it.
The pedagogical example for moving rvalue's is temporary strings and I'll show assignment in a constructor. If I have a class MyType that contains a string member variable, it can be initialized with an rvalue in the constructor like so:
class MyType{
const std::string m_name;
public:
MyType(const std::string&& name):m_name(name){};
}
This is nice because when I declare an instance of this class with a temporary object:
void foo(){
MyType instance("hello");
}
what happens is that we avoid copying and destroying the temporary object and "hello" is placed directly inside the owning class instance's member variable. If the object is heavier weight than a 'string' then the extra copy and destructor call can be significant.
After the call to GetString returns.
I wrote almost exactly the same class:
template <class C>
class _StringBuffer
{
typename std::basic_string<C> &m_str;
typename std::vector<C> m_buffer;
public:
_StringBuffer(std::basic_string<C> &str, size_t nSize)
: m_str(str), m_buffer(nSize + 1) { get()[nSize] = (C)0; }
~_StringBuffer()
{ commit(); }
C *get()
{ return &(m_buffer[0]); }
operator C *()
{ return get(); }
void commit()
{
if (m_buffer.size() != 0)
{
size_t l = std::char_traits<C>::length(get());
m_str.assign(get(), l);
m_buffer.resize(0);
}
}
void abort()
{ m_buffer.resize(0); }
};
template <class C>
inline _StringBuffer<C> StringBuffer(typename std::basic_string<C> &str, size_t nSize)
{ return _StringBuffer<C>(str, nSize); }
Prior to the standard each compiler did it differently. I believe the old Annotated Reference Manual for C++ specified that temporaries should clean up at the end of the scope, so some compilers did that. As late as 2003, I found that behaviour still existed by default on Sun's Forte C++ compiler, so StringBuffer didn't work. But I'd be astonished if any current compiler was still that broken.
StringBuffer is in the scope of GetString. It should get destroyed at the end of GetString's scope (ie when it returns). Also, I don't believe that C++ will guarantees that a variable will exist as long as there is reference.
The following ought to compile:
Object* obj = new Object;
Object& ref = &(*obj);
delete obj;
From cppreference:
All temporary objects are destroyed as the last step in evaluating the
full-expression that (lexically) contains the point where they were
created, and if multiple temporary objects were created, they are
destroyed in the order opposite to the order of creation. This is true
even if that evaluation ends in throwing an exception.
I am new here.
I am also new on C++
So here is the class and function i wrote.But i got the compiler error
My class:
class fooPlayer
{
public:
void fooPlayerfunc(){}//doing something here
char askYesNo(std::string question);
};
class fooPlayerFactory
{
public:
virtual std::auto_ptr<fooPlayer> MakePlayerX() const;
virtual std::auto_ptr<fooPlayer> MakePlayerO() const;
private:
std::auto_ptr<fooPlayer> MakePlayer(char letter) const;
std::auto_ptr<fooPlayer> my_player;
};
Implement my class:
auto_ptr<fooPlayer> fooPlayerFactory:: MakePlayer(char letter) const
{
my_player->fooPlayerfunc();
return my_player;
}
auto_ptr<fooPlayer> fooPlayerFactory::MakePlayerX() const
{
char go_first = my_player->askYesNo("Do you require the first move?");
MakePlayer(go_first);
return my_player;
}
auto_ptr<fooPlayer> fooPlayerFactory::MakePlayerO() const
{
return my_player;
}
My main() function here:
int main()
{
fooPlayerFactory factory;
factory.MakePlayerX();
factory.MakePlayerO();
}
I got the error:
error C2558: class 'std::auto_ptr<_Ty>' : no copy constructor available or copy constructor is declared 'explicit'
I do not know how to change it even after reading the document on this link:
The reason for the error is that you are calling the copy constructor of auto_ptr my_player in fooPlayerFactory::MakePlayerO() which is a const method. That means that is cannot modify its members.
However the copy constructor of auto_ptr DOES modify the right hand side so returning my_player trys to change its pointer to 0 (NULL), while assigning the original pointer to the auto_ptr in the return value.
The signature of the copy constuctor is
auto_ptr<T>::auto_ptr<T>(auto_ptr<T> & rhs)
not
auto_ptr<T>::auto_ptr<T>(const auto_ptr<T> & rhs)
The copy constructor of auto_ptr assigns ownership of the pointer to the left hand side, the right hand side then holds nothing.
I don't think you want to use auto_ptr here, you probably want boost::smart_ptr
It looks like you have mixed up two uses for auto_ptr
The first is as poor man's boost::scoped_ptr. This is to manage a single instance of a pointer in a class, the class manages the life time of the pointer. In this case you don't normally return this pointer outside your class (you can it is legal, but boost::smart_ptr / boost::weak_ptr would be better so clients can participate the life time of the pointer)
The second is its main purpose which is to return a newly created pointer to the caller of a function in an exception safe way.
eg
auto_ptr<T> foo() {
return new T;
}
void bar() {
auto_ptr<T> t = foo();
}
As I said I think you have mixed these two uses auto_ptr is a subtle beast you should read the auto_ptr docs carefully. It is also covered very well in Effective STL by Scott Meyers.
In your code:
auto_ptr<fooPlayer> fooPlayerFactory:: MakePlayer(char letter) const
{
my_player->fooPlayerfunc();
return my_player;
}
This is a const function, but fooPlayerfunc is not const - my compiler reports this error rather than the one you say you are getting. Are you posting the real code?
I don't think you actually want to constructing dynamic objects here.
A factory object creates and returns an object it normally does not keep a reference to it after creation (unless you are sharing it), and I don't actually see anywhere that you are creating the player.
If you only ever create one player internally in your (fooPlayerFactory). Then create an object and return references to it.
Edit: in response to the comment (which is correct, my bad), I left only the advice part.
Best practice is to have the factory methods just return a plain old pointer to the underlying object, and let the caller decide how to manage ownership (auto_ptr, scoped_ptr, or whatever).
Also your code is buggy, any class that implements virtual methods should have a virtual destructor.
I'm not seeing anywhere you construct my_player, so I have a feeling that some of the code is missing. Specifically, I think your constructor has this line:
my_player = new fooPlayer()
A fooPlayer object is not quite the same thing as an auto_ptr<fooPlayer> object, and auto_ptr is intentionally designed to prevent assigning from one to the other because, frankly, the alternative is worse. For the details, look up (1) conversion constructors, (2) the explicit keyword, and (3) copy constructors and destructive copy semantics.
You should change the constructor to either:
class fooPlayerFactory {
public:
fooPlayerFactory()
{
my_player = std::auto_ptr<fooPlayer>(new fooPlayer());
}
Or (using a member initializer list):
class fooPlayerFactory {
public:
fooPlayerFactory() : my_player(std::auto_ptr<fooPlayer>(new fooPlayer()) { }
The solution isn't pretty but, like I said, the alternative is worse due to some really arcane details.
As a bit of advice, though, you're making life harder than it needs to be; and may in fact be causing strange bugs. auto_ptr exists to manage the lifetime of an object, but the only reason you need to worry about the lifetime of my_player is that you've allocated it with new. But there's no need to call new, and in fact there's no need to keep my_player. And unless fooPlayerFactory is meant to be the base class for some other factory, there's no need to mark functions virtual.
Originally I thought you could get away with simply returning copies of the my_player object, but there's a problem: before returning my_player from MakePlayer() you call a method on it, and I assume that method changes the internal state of my_player. Further calls to MakePlayer() will change the state again, and I think you're going to eventually have my_player in the wrong state. Instead, return a different fooPlayer object with each request. Don't do memory management, just promise to construct the object. That way the user can decide on memory allocation:
fooPlayerFaclotry factory;
fooPlayer on_stack = factory.MakePlayerX();
fooPlayer* on_heap_raw_pointer = new fooPlayer(factory.MakePlayerO());
std::auto_ptr<fooPlayer> on_heap_managed_scope
= std::auto_ptr<fooPlayer>(factory.MakePlayerX());
I would change fooPlayerFactory to look like this:
class fooPlayerFactory
{
private:
fooPlayer MakePlayer(const char letter) const
{
fooPlayer result;
result.fooPlayerfunc();
return result;
}
public:
fooPlayer* MakePlayerX() const
{
char go_first = askYesNo("Do you require the first move?");
return MakePlayer(go_first);
}
fooPlayer MakePlayerO() const
{
return fooPlayer();
}
};
Does C++ provide a guarantee for the lifetime of a temporary variable that is created within a function call but not used as a parameter? Here's an example class:
class StringBuffer
{
public:
StringBuffer(std::string & str) : m_str(str)
{
m_buffer.push_back(0);
}
~StringBuffer()
{
m_str = &m_buffer[0];
}
char * Size(int maxlength)
{
m_buffer.resize(maxlength + 1, 0);
return &m_buffer[0];
}
private:
std::string & m_str;
std::vector<char> m_buffer;
};
And here's how you would use it:
// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);
std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
When will the destructor for the temporary StringBuffer object get called? Is it:
Before the call to GetString?
After GetString returns?
Compiler dependent?
I know that C++ guarantees that a local temporary variable will be valid as long as there's a reference to it - does this apply to parent objects when there's a reference to a member variable?
Thanks.
The destructor for that sort of temporaries is called at the end of the full-expression. That's the most outer expression which is not part of any other expression. That is in your case after the function returns and the value is evaluated. So, it will work all nice.
It's in fact what makes expression templates work: They can keep hold references to that sort of temporaries in an expression like
e = a + b * c / d
Because every temporary will last until the expression
x = y
Is evaluated completely. It's quite concisely described in 12.2 Temporary objects in the Standard.
litb's answer is accurate. The lifetime of the temporary object (also known as an rvalue) is tied to the expression and the destructor for the temporary object is called at the end of the full expression and when the destructor on StringBuffer is called, the destructor on m_buffer will also be called, but not the destructor on m_str since it is a reference.
Note that C++0x changes things just a little bit because it adds rvalue references and move semantics. Essentially by using an rvalue reference parameter (notated with &&) I can 'move' the rvalue into the function (instead of copying it) and the lifetime of the rvalue can be bound to the object it moves into, not the expression. There is a really good blog post from the MSVC team on that walks through this in great detail and I encourage folks to read it.
The pedagogical example for moving rvalue's is temporary strings and I'll show assignment in a constructor. If I have a class MyType that contains a string member variable, it can be initialized with an rvalue in the constructor like so:
class MyType{
const std::string m_name;
public:
MyType(const std::string&& name):m_name(name){};
}
This is nice because when I declare an instance of this class with a temporary object:
void foo(){
MyType instance("hello");
}
what happens is that we avoid copying and destroying the temporary object and "hello" is placed directly inside the owning class instance's member variable. If the object is heavier weight than a 'string' then the extra copy and destructor call can be significant.
After the call to GetString returns.
I wrote almost exactly the same class:
template <class C>
class _StringBuffer
{
typename std::basic_string<C> &m_str;
typename std::vector<C> m_buffer;
public:
_StringBuffer(std::basic_string<C> &str, size_t nSize)
: m_str(str), m_buffer(nSize + 1) { get()[nSize] = (C)0; }
~_StringBuffer()
{ commit(); }
C *get()
{ return &(m_buffer[0]); }
operator C *()
{ return get(); }
void commit()
{
if (m_buffer.size() != 0)
{
size_t l = std::char_traits<C>::length(get());
m_str.assign(get(), l);
m_buffer.resize(0);
}
}
void abort()
{ m_buffer.resize(0); }
};
template <class C>
inline _StringBuffer<C> StringBuffer(typename std::basic_string<C> &str, size_t nSize)
{ return _StringBuffer<C>(str, nSize); }
Prior to the standard each compiler did it differently. I believe the old Annotated Reference Manual for C++ specified that temporaries should clean up at the end of the scope, so some compilers did that. As late as 2003, I found that behaviour still existed by default on Sun's Forte C++ compiler, so StringBuffer didn't work. But I'd be astonished if any current compiler was still that broken.
StringBuffer is in the scope of GetString. It should get destroyed at the end of GetString's scope (ie when it returns). Also, I don't believe that C++ will guarantees that a variable will exist as long as there is reference.
The following ought to compile:
Object* obj = new Object;
Object& ref = &(*obj);
delete obj;
From cppreference:
All temporary objects are destroyed as the last step in evaluating the
full-expression that (lexically) contains the point where they were
created, and if multiple temporary objects were created, they are
destroyed in the order opposite to the order of creation. This is true
even if that evaluation ends in throwing an exception.