Is modifying data passed by const shared_ptr& Ok? - c++

I've come across a situation where I needed to set a property to a library object by means of a setter accepting const shared_ptr reference. Here is a simple example:
// library class
class WidgetProxy {
public:
void setName(const std::shared_ptr<std::string>& name);
// more methods
};
Suspecting nothing, I used it like this:
WidgetProxy widgetProxy(...);
auto name = std::make_shared<std::string>("Turing");
widgetProxy.setName(name);
// continue using `name`
Then I've found out that name had become empty after setName() call. Luckily, library source code was available and I was able to examine the implementation. It was roughly the following:
class WidgetImpl {
public:
void setName(std::string name)
{
name_ = std::move(name);
}
private:
std::string name_;
};
void WidgetProxy::setName(const std::shared_ptr<std::string>& name)
{
widgetImpl_.setName(std::move(*name));
}
So setName() moves out the string wrapped by the shared_ptr which is formally not prohibited since shared_ptr template argument is std::string and not const std::string.
My questions:
Is it a normal design to implement WidgetProxy::setName() like this?
Should a library user normally expect such behavior when they see a const shared_ptr<T>& function parameter?
Upd: The posted code snippets are much simplified. In the library there is a different type in place of std::string. I have also omitted checks for pointer validity.

Is it a normal design to implement setName() like this?
This implementation style is OK:
void setName(std::string name)
{
name_ = std::move(name);
}
The string is first copied by the function call, and the copied string is moved to the class member. The resulting code is as efficient than passing a reference to a string, and then copying to the data member.
This one is not. And I do not not recommend it.
void WidgetProxy::setName(const std::shared_ptr<std::string>& name)
{
widgetImpl_.setName(std::move(*name));
}
For 2 reasons. 1: why require a std::shared_ptr if the pointer is not kept? 2: The net result of the operation deletes the string held by the pointee. This affects all the other holders of the shared_ptr, some of which may need the value of the original string.
A more correct way to write this function, and the associated function call:
void WidgetProxy::setName(std::string name)
{
widgetImpl_.setName(std::move(name));
}
// call as:
if (strPtr)
proxy.setName(*strPtr); // with strPtr being a std::shared_ptr<std::string>
Should a library user normally expect such behavior when they see a const shared_ptr& function parameter?
No. This is a terrible way of coding a library. If the caller wishes to keep the string for any reason, he must create a shared_ptr with a copy of the original string. Plus, the library code does not even check if the shared_ptr holds a valid pointer! Very, very naughty.

You misunderstand what this means:
class WidgetProxy {
public:
void setName(const std::shared_ptr<std::string>& name);
};
setName takes a reference to a possibly mutable shared pointer that it does not have permission to modify. This shared pointer refers to a mutable string.
This means within setName, whenever control flows out of what is visible to the compiler, the pointer and validity of name could change (and, you should check that it does not).
The value pointed to by this non-mutable view of a possibly mutable shared pointer is fully mutable. You have full permission to modify it.
Some alternatives:
class WidgetProxy {
public:
void setName(std::shared_ptr<std::string> name);
};
This is a local shared pointer to a mutable string. It can only be modified locally, unless you leak references to it. The data referred to be be manipulated by any other code, and must be assumed to be modified whenever local context is left. It will, however, remain a valid pointer over the lifetime of the setName function unless you personally clear it.
class WidgetProxy {
public:
void setName(std::shared_ptr<std::string const> name);
};
this is a local shared pointer to a string you do not have mutation rights to. Someone else with a shared pointer to it could modify it if it is actually mutable at any point you leave local code, and should be presumed to be doing so.
class WidgetProxy {
public:
void setName(std::string name);
};
this is a local copy of a buffer of characters that nobody else can modify within the function, and that you own.
class WidgetProxy {
public:
void setName(std::string const& name);
};
this is a reference to a possibly mutable external std::string which must be presumed to be changed every time you leave local code in the function.
Personally, I see no reason why WidgetProxy is taking an arguments by shared_ptr or const&. It doesn't use the shared-ness of the argument, nor does it want the value to be remotely changed on it. It is a "sink" argument that it will consume, and the cost of moving the object is low.
WidgetProxy::setName should take a std::string. Sink arguments of cheap-to-move data should take by-value. And use of smart pointers here seems like a horrid idea; why complicate your life with shared_ptr?

It is perfectly fine for WidgetImpl::setName() to be implemented in this manner, as it is moving from local parameter.
It is simply a bug to implement WidgetProxy::setName this way, because you can't realistically expect the object managed by shared_ptr to be movable.

Related

Is it a good practice to make a method which modifies data outside the class const?

I would like to ask a question about methods' const-correctness. Let me illustrate the situation.
class MyClass
{
public:
...
void DiscussedMethod() { otherClass->NonConstMethod(); }
private:
OtherClass *otherClass;
};
I have a class MyClass which keeps a pointer to OtherClass. In DiscussedMethod it calls OtherClass::NonConstMethod which modifies some visible data.
I would like to know, whether it would be a good practice to make the DiscussedMethod const (since it doesn't modify any member data)? Would it be a bad practice? Or is both fine?
What if the OtherClass kept a pointer to the MyClass and in NonConstMethod modified some of the MyClass' data (meaning that the MyClass member data would change during the DiscussedMethod call). Would it be a bad practice to make the DiscussedMethod const then?
As far as I've been able to find out, the const on a method is mostly a code documenting thing, so I would probably lean toward to not making the DiscussedMethod const, but I would like to hear your opinions.
EDIT: Some replies take the into account whether the object pointed to by otherClass is owned by the MyClass object. This is not the case in the scenario I'm working with. Lets say that both objects exist independently side by side (with the ability to modify each other). I think this analogy describes my situation quite well.
For example consider something like doubly-linked list, where each element is a class that keeps pointer to its neighbours and member variable color. And it has method MakeNeighboursRed which changes the color of its neighbours but doesn't affect the calling object's state itself. Should I consider making this method const?
And what if there was some possibility that MakeNeighboursRed would call neighbour's MakeNeighboursRed. So in the end the state of the object for which MakeNeighboursRed has been called originally would change as well.
And I would like to thank you all for your opinions :-)
If MyClass owns the OtherClass instance i wouldn't make DiscussedMethod constant.
The same goes for classes, managing resources. I.e. the standard containers do not return non const references or pointers to the managed memory using const functions, although it would be "possible" (since the actual pointer holding the resource is not modified).
Consider
class MyClass
{
public:
bool a() const { return otherClass->SomeMethod(); }
void b() const { otherClass->NonConstMethod(); }
private:
OtherClass *otherClass;
};
void foo (MyClass const &x)
{
cout << boolalpha << x.a() << endl;
x.b(); // possible if b is a const function
cout << boolalpha << x.a() << endl;
}
The foo could print two different values although an implementor of foo would probably expect that two function calls on a const object will have the same behaviour.
For clarification:
The following is invalid according to the standard since the const version of operator[] returns std::vector<T>::const_reference which is a constant reference to the value type.
std::vector<int> const a = { /* ... */ };
a[0] = 23; // impossible, the content is part of the state of a
It would be possible if there was only one signature of this function, namely referece operator[] (size_t i) const;, since the operation does not alter the internal pointers of the vector but the memory they point to.
But the memory, managed by the vector is considered to be part of the vectors state and thus modification is impossible through the const vector interface.
If the vector contains pointers, those pointer will still be unmodifiable through the public const vector interface, although the pointers stored in the vector may well be non const and it may well be possible to alter the memory they point to.
std::vector<int*> const b = { /* ... */ };
int x(2);
b[0] = &x; // impossible, b is const
*b[0] = x; // possible since value_type is int* not int const *
In OOP object should be fully described by its state, available through its interface. Thus, const methods should not alter object's state, if these changes might be observed through the interface.
A good example is a mutable mutex inside your class to guard some shared resources. It might be modified from const method, since it does not introduce any changes observable via class interface.
General rule of thumb is, that if you can make a member function const, you probably should. The reason for that is that it allows you to catch unintended behaviour and bug easier.
Another argument in favor would be that if you have this function as const you are allowed to call it on const object, so it isn't really a documentation thing.
Overall it depends what the other class is. It's not black and white...
If otherClass is a log object (for example) and you want to log the operation of the current object then it's perfectly fine calling it from a const function.
If the otherClass is a container that for design (or implementation) purposes is implemented as a separate object than effectively a const function modifies the object making this a very bad idea.
I hope this helps.
It's totaly incorrect to make DiscussedMethod const as it changes it's *this state. The only loophole to this is making non-logically-part-of-object's-state member data mutable so they can be changed in const functions. This would be things like a member that hold a count for "number of times function x() has been called". Any thing else is part of the object's state, and if a function changes it (at any level), that function isn't const.
I would like to know, whether it would be a good practice to make the DiscussedMethod const (since it doesn't modify any member data)?
otherClass is member data, and it (or rather, the object it points to) gets modified.
Consider the semantics should the pointer to otherClass be refactored to a fully-owned object... whether something is held as a pointer, reference, or object doesn't change the semantical ownership, IMO.

How to use a std::string without copying?

I have a class say,
class Foo
{
public:
void ProcessString(std::string &buffer)
{
// perform operations on std::string
// call other functions within class
// which use same std::string string
}
void Bar(std::string &buffer)
{
// perform other operations on "std::string" buffer
}
void Baz(std::string &buffer)
{
// perform other operations on "std::string" buffer
}
};
This class tries to use a std::string buffer to perform operations on it using various methods under these conditions:
I don't want to pass a copy of std::string which I already have.
I don't want to create multiple objects of this class.
For example:
// Once an object is created
Foo myObject;
// We could pass many different std::string's to same method without copying
std::string s1, s2, s3;
myObject.ProcessString(s1);
myObject.ProcessString(s2);
myObject.ProcessString(s3);
I could use the string and assign it as a class member so that other functions using can know about it.
But it seems we cannot have a reference class member std::string &buffer because it can only be initialized from constructor.
I could use a pointer to std::string i.e. std::string *buffer and use it as a class member and then pass the addresses of s1, s2, s3.
class Foo
{
public:
void ProcessString(std::string *buf)
{
// Save pointer
buffer = buf;
// perform operations on std::string
// call other functions within class
// which use same std::string string
}
void Bar()
{
// perform other operations on "std::string" buffer
}
void Baz()
{
// perform other operations on "std::string" buffer
}
private:
std::string *buffer;
};
Or, the other way could be pass each functions a reference to std::string buffer just as shown in the first example above.
Both ways kind of seem a bit ugly workarounds to be able to use a std::string without copying as I have rarely seen the usage of std::string as a pointer or pass all the functions of class the same argument.
Is there a better around this or what I'm doing is just fine?
Keeping in MyObject a reference or a pointer to a string which is not ownned by your object is dangerous. It will be easy to get nasty undefined behaviour.
Look at the following legal example (Bar is public):
myObject.ProcessString(s1); // start with s1 and keep its address
myObject.Bar(); // works with s1 (using address previously stored)
Look at the following UB:
if (is_today) {
myObject.ProcessString(string("Hello")); // uses an automatic temporary string
} // !! end of block: temporary is destroyed!
else {
string tmp = to_string(1234); // create a block variable
myObject.ProcessString(tmp); // call the main function
} // !! end of block: tmp is destroyed
myObject.Bar(); // expects to work with pointer, but in reality use an object that was already destroyed !! => UB
The errors are very nasty, because when reading function's usage, everything seems ok and well managed. The problem is hidden by automatic destruction of bloc variables.
So if you really want to avoid the copy of the string, you could use a pointer as you envisaged, but you shall only use this pointer in functions called directly by ProcessString(), and make these functions private.
In all other case, I'd strongly suggest to reconsider your position, and envisage:
a local copy of the string in the object that shall use it.
Or use a string& parameters in all the object's function that need it. This avoids the copies but leaves to caller the responsibility of organising the proper management of the string.
You basically need to answer this question: who owns the string? Does Foo own the string? Does the external caller own the string? Or do they both share ownership of the string.
"Owning" the string means that the lifetime of the string is tied to it. So if Foo owns the string, the string will stop existing when Foo stops existing or destroys it. Shared ownership is far more complicated, but we can make it simpler by saying that the string will exist as long as any of the owners keep it.
Each situation has a different answer:
Foo owns the string: Copy the string into Foo, then let the member methods mutate it.
External resource owns the string: Foo should never hold a reference to the string outside of its own stack, since the string could be destroyed without its knowledge. This means that it needs to be passed by reference to every method that uses it and does not own it, even if the methods are in the same class.
Shared ownership: Use a shared_ptr when creating the string, then pass that shared_ptr to every instance that shares ownership. You then copy the shared_ptr to a member variable, and methods access it. This has much higher overhead then passing by reference, but if you want shared ownership it is one of the safest ways to do so.
There are actually several other kinds of ways to model ownership, but they tend to be more esoteric. Weak ownership, transferable ownership, etc.
Since your requirement is that
1.I don't want to pass a copy of std::string which I already have.
2.I don't want to create multiple objects of this class.
using pass by ref would be the solution to 1
using static would be the solution to 2. since it is a static memeber method, there would be only one copy of this method. it wont belong to any object, though. With that being said, you can call this method directly instead of through an object.
For example,
class Foo
{
static void ProcessString(std::string &s)
{
// perform operations on std::string
// call other functions within class
// which use same std::string string
}
}
when you call this method, it would be something like this:
std::string s1, s2, s3;
Foo::ProcessString(s1);
Foo::ProcessString(s2);
Foo::ProcessString(s3);
One step further, if you want only one instance of this class, you can refer to singleton design pattern.

Returning strings by reference cpp

Forgive me if this has been asked before, I am sure it has but I couldn't find an answer I was happy with.
I am coming to cpp from a heavy Java background and would like to understand when to return a reference/pointer to an object rather than a copy.
for the following class definition:
class SpaceShip {
string name;
WeaponSystem weaponSystem; //represents some object, this is just an example, I dont have this type of object at all in my program
int hull;
string GetName() const {
return name;
}
WeaponSystem GetWeaponSystem() const {
return weaponSystem;
}
int GetHull() const {
return hull;
}
};
I know that returning a copy of things is expensive, I would think this means I want to avoid returning something like a string or weaponSystem by value, but an int by value is ok.
Is this right? I also know that I need to be aware of where things live in memory, does returning a reference to something in this class mean danger down the line if this object is destroyed and something still owns a reference to it's name?
On your last point, you definitely need to be a lot more careful about resource management in C++ than in Java. In particular, you need to decide when an object is no longer needed. Returning by reference has an effect of aliasing to the returned object. It is not noticeable when the object you are sharing is immutable, but unlike Java's Strings, C++ string are mutable. Therefore if you return name by value and then rename your SpaceShip, the caller would see the old name even after the renaming. If you return by reference, however, the caller will see a change as soon as ShaceShip is renamed.
When you deal with copying complex objects, you can decide how much is copied by providing a custom implementation of a copy constructor. If you decide to provide a copy constructor, don't forget the rule of three, and override the other two.
It "works" but you should have
const string& GetName() const {
It may also be beneficial to have the following also
const WeaponSystem& GetWeaponSystem() const {
Also, class is private by default, as such, your accessor functions are private.
the thing you have to know is every getter of your class must be prototype like that :
const <type> &className::getXXX() const
{
...
}
and every setter you make like that :
void className::setXXX(const <type> &)
{
...
}
Use reference when it's possible.
Sometimes, with complex object you can use pointer. That's depend on your code structure.

Changing a class to its child class

I'm trying to make each instance of a class (named Caller here) have an instance of another class (Target). The point is that the second class has numerous children and I need to be able to have the Caller class switch among them at will. I have tried several ways, but not one gave me any desirable results. Current code:
class Target
{
public:
virtual void do_something()
{ log_message("NO!"); }
};
class TargetChild : public Target
{
public:
virtual void do_something()
{ log_message("YES!"); }
};
class Caller
{
private:
Target target;
public:
void call_target()
{ target.do_something(); }
void set_target(Target set_target)
{ target = set_target; }
};
int main( int argc, const char* argv[] )
{
TargetChild targetChild;
Caller caller;
caller.call_target();
caller.set_target(targetChild);
caller.call_target();
}
The wanted result in the log file is "NO! YES!" but instead it writes the NO! twice. I can't really see what's wrong with it.
You cannot change the type of an object in C++. You can only create, destroy, copy, and (in C++11) move data. In this case, you've copied the data from the subclass object to the base class object. This copied an empty subset of an empty subset. The problem you observed is called "slicing."
Probably what you want is a member containing a function pointer that can be changed. virtual gets you a function pointer but it can't be changed. Try std::tr1::function, boost::function or C++11 std::function.
Or, if you really want to go the virtual route, use a Target * pointer. Best to use a smart pointer class such as unique_ptr< Target > (again Boost/TR1/C++11) or std::auto_ptr< Target > (old-fashioned C++03). You can also do it yourself with new and delete, but such code doesn't really work as well, and is only suitable for a little educational tinkering.
Your code is suffering from object slicing. Even though targetChild in main is a TargetChild, it's passed by value to Caller::set_target, which means it's copied to a local variable which has type Target. To get around object slicing in general, you must use pass-by-reference or use pointers.
In this case, since you wish for Caller to access the passed object outside the Caller::set_target method, you should use a pointer. References alone won't work because though you could make Caller::target a reference, you couldn't change the object it referred to.
Pointers introduce memory management problems, as you must ensure the TargetChild is deallocated (otherwise the program has a memory leak), but not too soon (which will cause access violations, most likely crashing your program). The boost library has various smart pointer classes to make this easier. The C++ standard auto_ptr class could also be used, if only one other class should own the TargetChild instance at any one point in time.
Use an interface, ITarget and switch them at will
ITarget
virtual void do_something() { log_message("NO!"); }
Treat everything as Type of ITarget
This a neat way of handling it.
My c++ is rusty :)
Use pointers instead. More about polymorphism: http://www.cplusplus.com/doc/tutorial/polymorphism/
...
class Caller
{
private:
Target* target;
public:
Caller() { target = NULL; }
void call_target() { if (target != NULL) target->do_something(); }
void set_target(Target* set_target) { target = set_target; }
};
int main( int argc, const char* argv[] )
{
....
caller.set_target(&targetChild);
...
}
In set_target you are passing targetChild by value, there you are loosing the chance to call TargetChild::do_something. You need to extend caller to include a reference (or pointer) to the current target, the reference (or pointer) will keep the information about the original TargetChild and then the compiler will still call TargetChild::do_something.

Keeping a reference instead of a pointer?

I have a class which basically is a text manager. It can draw text and whatnot. I basically want the color and text std::string to only be a constant reference. Would it then be alright to do
class TextManager {
const std::string &text;
void draw(const std::string &text) const;
public:
TextManager(const std::string &text)
{
this->text = text;
}
void someMethod()
{
draw(text);
}
};
I want when the class that owns an instance of TextManager's text changes, the change is reflected in the TextManager.
would I be better off using a pointer?
thanks
If you never need to re-seat the reference (i.e. refer to a different object), then it's fine. But in my experience, you'll inevitably find out later down the line that you need to be more flexible, in which case a reference is a pain. It may be better to go with a pointer from the start.
But note that you can only initialise a member variable of reference type in the constructor initialiser list. (Also, you probably want to declare that constructor as explicit).
This code doesn't compile. this->text = text doesn't do what you think it does - it's not like Java where assigning a reference is like changing the pointer. reference = value will actually invoke the copy operator, so it will copy the value of the rhs to the lhs, either as member-by-member copy or using the operator= if it was overridden. Since your text is const, you can't do that.
So in this case, you have to use a pointer - references cannot be modified once initialized.
EDIT: Just to explain ways in which you could use a reference:
const std::string &text = yourString;
or:
TextManager(const std::string &textRef)
: text(textRef)
{
}
That way, you have a permanent reference to whatever string you have.
Once you have sorted out the initialisation (which other comments can help you with), using a reference will let you do what you want. That is, changes to the referenced std::string will affect your class because they are the same std::string.
You can get similar behaviour using std::string const* instead of std::string const&. As Oli brought out, using a pointer is more flexible. Since a pointer can be null and can be updated using a pointer will allow you to define a default constructor and a (probably compiler generated) assignment operator. Which may not be important in this class but likely will be in some other class you will write (eg if you want to put objects of this class into a std::vector). So you probably are better off using a pointer internally. Though you may wish to still pass a reference to the constructor and take the address of it to initialise the member.