Can you explain these lines?
class HasPtr {
public:
HasPtr(const std::string &s = std::string())://this line
ps(new std::string(s)), i(0) { } //and this
HasPtr(const HasPtr &p):
ps(new std::string(*p.ps)), i(p.i) { }
HasPtr& operator=(const HasPtr &);
~HasPtr() { delete ps; }
private:
std::string *ps;
int i;
};
This topic in book is about classes that act like values.
In this declaration of a constructor
HasPtr(const std::string &s = std::string())://this line
ps(new std::string(s)), i(0) { }
there is used the default argument std::string() and the mem-initializer list
ps(new std::string(s)), i(0)
that is executed before the control will be passed to the constructor body. As there is nothing to do in the body the body of the constructor is empty.
So you can call the constructor without an argument like
HasPtr obj;
in this case an empty string created like string() will be used as an argument.
const std::string &s is a reference to a const instance of std::string.
= std::string() is a default value. xyz() is a syntax for a value-initialized instance of xyz.
So when HasPtr is instantiated without an argument (e.g. HasPtr()), the HasPtr(s) constructor will be invoked with s bound to a temporary blank std::string instance (which lives until the end of the full-expression, usually the first ;).
Then ps will be initialized with new std::string(s), making a copy of s on the heap and storing a pointer to it in ps.
If HasPtr is invoked with an actual argument, the = std::string() part will not execute.
Related
I'm getting this error as soon as I define a destructor, but without that the compilation succeed, but I badly want to define destructor to debug some seg faults.
class Socket {
private:
seastar::output_stream<char> socket;
public:
std::string peer;
public:
Socket() = default;
template <typename... Args>
explicit Socket(seastar::output_stream<char> &&s, std::string p) : socket(std::move(s)), peer(p) {}
~Socket() {
std::cout << "Socket has gone out of scope" << "\n";
}
seastar::future<> send(std::string message) {
co_await socket.write(message);
co_await socket.flush();
}
seastar::future<> close() {
co_await socket.close();
}
};
Compilation fails with,
error: object of type 'Socket' cannot be assigned because its copy assignment operator is implicitly deleted
connection->second.socketObj = std::move(socketObj);
^
./socketwrapper.h:44:46: note: copy assignment operator of 'Socket' is implicitly deleted because field 'socket' has a deleted copy assignment operator
seastar::output_stream<char> socket;
Is there anyway to fix this issue?
The underlying question here is "Why is the compiler trying to use a copy-assignment when I'm explicitly using std::move()?"
So let's see a simple, well-formed example:
struct MyStruct {
MyStruct()
: some_data(new int(12)) {}
MyStruct(const MyStruct& other)
: some_data(new int(*other.some_data)) {}
MyStruct& operator=(const MyStruct& rhs) {
delete some_data;
some_data = new int(*rhs.some_data);
return *this;
}
~MyStruct() {
delete some_data;
}
int * some_data;
};
MyStruct foo() {
return MyStruct();
}
int main() {
MyStruct a;
a = foo(); // <--- copy-assignment here, no choice.
}
It's pretty obvious that's it's important for the copy-assignment to be used, despite it being a RValue scenario.
But why is that program well-formed in the first place? It's a move-assignment setup and I have no move-assignment operator. Can't the compiler just give me a slap on the fingers? The thing is, this was well-formed before C++11 and move-semantics were a thing, so it must keep behaving correctly.
So, in the presence of any other constructors/destructor/assignment-operator, if there is no move assignment/constructor present, the copy assignment/copy-constructor must be used instead, just in case it happens to be code that was written a long time ago.
The immediate fix for you is to add a move-assignment operator. At that point, it might also help to clean things up and complete the full rule-of-5.
class Socket {
private:
seastar::output_stream<char> socket;
public:
std::string peer;
public:
Socket() = default;
explicit Socket(seastar::output_stream<char> &&s, std::string p)
: socket(std::move(s)), peer(p) {}
Socket(Socket&&) = default;
Socket& operator=(Socket&&) = default;
// These are technically redundant, but a reader wouldn't know it,
// so it's nice to be explicit.
Socket(const Socket&) = delete;
Socket& operator=(const Socket&) = delete;
// ...
Add
Socket(Socket&&)=default;
Socket& operator=(Socket&&)=default;
I have question. Let's have this code:
#include <iostream>
#include <string>
#include <memory>
class Writable {
public:
virtual ~Writable() = default;
virtual void write(std::ostream& out) const = 0;
};
class String : public Writable {
public:
String(const std::string& str) : m_str(str) {}
virtual ~String() override = default;
virtual void write(std::ostream& out) const override { out << m_str << '\n'; }
private:
std::string m_str;
};
class Number : public Writable {
public:
Number(double num) : m_num(num) {}
virtual ~Number() override = default;
virtual void write(std::ostream& out) const override { out << m_num << '\n'; }
private:
double m_num;
};
int main() {
std::unique_ptr<Writable> str1(new String("abc"));
std::unique_ptr<Writable> num1(new Number(456));
str1->write(std::cout);
num1->write(std::cout);
}
I dont understand why unique_pointers are defined like this:
std::unique_ptr<Writable> str1(new String("abc"));
Its some kind of shorthand? Or I must do it this way? Is there some kind of equivalent? For example like:
std::unique_ptr<Writable> str1 = std::unique_ptr<String>(new String("abc"));
Here you are creating a new unique_ptr and initializing with a raw pointer returned by new operator.
std::unique_ptr<Writable> str1(new String("abc"));
Here you are creating a new unique_ptr and initializing with a raw pointer returned by new operator and move constructing another unique_ptr with it.
std::unique_ptr<Writable> str1 = std::unique_ptr<String>(new String("abc"));
However compiler can (most likely) perform move elison and make the above two equivalent.
The right way to initialize from c++14 and later is below
std::unique_ptr<Writable> v1 = std::make_unique<String>();
The form of initialization in
std::unique_ptr<Writable> str1(new String("abc"));
is called direct initialization. If the constructor is marked explicit (like in explicit unique_ptr(pointer p) noexcept constructor), this form of initialization is required.
explicit constructor disables copy initialization in the form of std::unique_ptr<Writable> str1 = new String("abc");.
Just like you can write
std::vector<int> foo(10);
to create a vector of 10 int's
std::unique_ptr<Writable> str1(new String("abc"))
creates a std::unique_ptr<Writable> that points to a new String("abc"). It is the same as doing
std::vector<int> foo = std::vector(10);
and
std::unique_ptr<Writable> str1 = std::unique_ptr<String>(new String("abc"));
except that the later cases use copy initialization which can be different in some cases.
To save on some typing you could use
auto str1 = std::make_unique<String>("abc");
instead when you declare your unique_ptr's
I understand that the he implicit copy constructor/assignment operator does a member-wise copy of the source object.
Say my class has 1000 members. I want to suppress ONE of the member when doing assignment assignment(and the default value applies), the other 999 members still use the member-wise copy as the implicit assignment operator.
For example:
class Foo
{
std::string s1;
std::string s2;
std::string s3;
....
std::string s1000;
};
Then we fill object f1 with some values:
Foo f1;
f1.s1 = "a";
f1.s2 = "b";
f1.s3 = "c";
...
Now we copy assign f1 (source) to f2 (target)
Foo f2 = f1;
How can I achieve the following result if I want to suppress "s2"?
assert(f2.s1 == "a");
assert(f2.s2 == ""); //default value
assert(f2.s3 == "c");
I understand that provide a copy constructor/assignment operator will solve this problem.
class Foo
{
Foo( const Foo& other)
{
s1 = other.s1;
//s2 = other.s2; //suppress s2
s3 = other.s3;
...
s1000 = other.s1000;
};
Foo& Foo::operator=( const Foo& other)
{
s1 = other.s1;
//s2 = other.s2; //suppress s2
s3 = other.s3;
...
s1000 = other.s1000;
return *this;
};
std::string s1;
std::string s2;
std::string s3;
....
std::string s1000;
};
However, I have 1000 members. I don't want to implement such big functions.
If I implement function like this:
class Foo
{
Foo( const Foo& other)
{
*this = other;
s2 = "";
};
Foo& Foo::operator=( const Foo& other)
{
*this = other;
s2 = "";
return *this;
};
}
Obviously, that's endless recursive.
Here is the only choice for me at the moment, which is:
Foo f2 = f1;
f2.s2 = "";
However, suppose there are thousands of Foo f2 = f1; statements in my project. Finding them all to append one line after them is way too hard.
So, I want the minimum code change to customize the member-wise copy of an object. How can I do this?
I too agree with #gsamaras that you must remember the single responsibility principle. But unlike their answer, I think you can have your cake and eat it too.
Let's examine the responsibilities of your class. For one, it didn't care how all the data members were copied. That responsibility was delegated to the type that each member belonged to. We should maintain that, since this realization makes clear who should be responsible.
The data member in question, s2 is a std::string. That type copies itself. But what if we wrap it?
template<typename T>
class suppress_copies {
T _mem;
public:
// Allow changing the held member
operator T&() { return _mem; }
T& get() { return _mem; }
suppress_copies() = default;
// But stop automatic copies (potentially even handles moves)
suppress_copies(suppress_copies const&) {} // default initialize the member
suppress_copies& operator=(suppress_copies o) { // Accept default initialized "other"
using std::swap;
swap(_mem, o._mem);
return *this;
}
};
And that's pretty much it, this is the type that's responsible for suppressing the copy. Just designate the member with this wrapper:
suppress_copies<std::string> s2;
Have you heard about the Single responsibility principle? You are violating it with using too many data members for your class. Big functions and big classes are a nest for bugs, misunderstanding, and unwanted side effects. Just imagine the person that will maintain your code in the future..
As a result do not expect to get away with this that easily (I mean just a search and replace on your project is not that hard).
How to really cope with this problem?
Refactor!
Use composition with compact classes targetting only at what they have to really do.
Unfortunately, you can't invoke the compiler's default copy behavior for a class while also implementing custom copy behavior in the same class. If you perform custom copy construction/assignment, you will have to manually copy the 999 members while suppressing the 1 member.
You can implement the copy constructor in terms of the assignment operator, or vice versa, to avoid duplicating the copying code. For example:
class Foo {
...
public:
Foo(const Foo& other) :
s1(other.s1),
//s2(other.s2), //suppress s2
s3(other.s3),
...
s1000(other.s1000)
{
}
Foo& operator=(const Foo& other) {
if (&other != this) {
Foo(other).swap(*this);
}
return *this;
}
void swap(Foo &other) {
std::swap(s1, other.s1);
std::swap(s2, other.s2);
std::swap(s3, other.s3);
...
std::swap(s1000, other.s1000);
}
...
};
Yes, it is tedious work to setup (but then, so is having a class with 1000 data members to begin with. Consider refactoring the class into smaller pieces!). Once it is done, you don't have to worry about it anymore.
A simpler solution is to write a separate class just for s2 and disable its ability to copy its data. For example:
class string_nocopy {
std::string m_str;
public:
string_nocopy(const std::string &s = std::string()) : m_str(s) {}
string_nocopy(const string_nocopy &) : m_str() {}
string_nocopy& operator=(const std::string &s) {
m_str = s;
return *this;
}
string_nocopy& operator=(const string_nocopy &other) {
if (&other != this) m_str = "";
return *this;
}
operator std::string() { return m_str; }
...
};
Then you don't need a custom copy constructor or copy assignment operator in Foo, the defaults will suffice:
class Foo {
...
std::string s1;
string_nocopy s2;
std::string s3;
...
std::string s1000;
};
The most idiomatic way would be to have the members that need special processing know how to do it themselves (as in, embedded in their copy constructor), so to keep the copy constructor/assignment operator of aggregates always to the default. That's the idea behind having std::vector have its own copy constructor instead of having aggregates deal manually with each array they own.
This can work as long as the required behavior is general enough to stand on its own, and does not depend much from the rest of the aggregate; this is probably not your case - which poses the extra problems that (1) having an "autoreset" string (which only makes sense in the context of your class) as a member of your public interface is probably a bad idea, and (2) that inheriting from STL containers is problematic (although in this case it would work, since nobody would destroy it polymorphically).
So, for the cases where delegating to the member itself doesn't work, the only way out of this kind of problems (keep the default copy constructor/assignment operator but do some custom processing) that I found unfortunately is through an auxiliary struct. Put all the "normal" members into a FooAux structure with default copy constructor and assignment operator. Then Foo will inherit from this and add just the members that require special treatment; the copy constructor and assignment operator will delegate most of the work to the base class, adding just the custom processing for the extra members.
0. As it's been said by #gsamaras, you probably need to redisign you class.
But if for some reason currently this is not an option, well, there are some tricks possible.
If those members are all of the same type, then store them in a container (e.g. std::array) rather than in thousand members.
Otherwise, hide the members inside an inner private structure with default assignment. Then, in the outer class' operator=, first remember current value of the muted member, then assign the structure, then restore muted member to the previous value.
This is actually easier than you might imagine.
Declare a new string type, derived from std::string which has specialised copy behaviour. Then simply use the default copy/move behaviour in your outer class.
struct copyless_string : std::string
{
// delegte constructors to base class
using std::string::string;
// implement custom copy/assignment
copyless_string(copyless_string const& str)
: std::string()
{}
copyless_string& operator=(copyless_string const& str)
{
clear();
return *this;
}
// and default move behaviour
copyless_string(copyless_string && str) = default;
copyless_string& operator=(copyless_string && str) = default;
};
struct my_class
{
std::string s1, s2, s3, s4;
copyless_string s5; // <--- won't be copied
std::string s6, s7, s8, s9, s10;
};
Another way:
Defer the non-copy parts of the class to a base class and handle them separately.
Then use the rule of zero to avoid writing any general case copy behaviour at all.
#include <string>
#include <cassert>
struct CopylessFoo
{
CopylessFoo() : s2() {}
CopylessFoo(CopylessFoo const& other)
: CopylessFoo()
{}
CopylessFoo& operator=(CopylessFoo const& other)
{
s2.clear();
return *this;
}
CopylessFoo(CopylessFoo&& other) = default;
CopylessFoo& operator=(CopylessFoo&& other) = default;
std::string s2;
};
struct Foo : CopylessFoo
{
// rule of zero - no copy/assignment necessary
std::string s1;
// s2 provided by base class
std::string s3;
// ....
std::string s1000;
};
int main()
{
Foo f;
f.s1 = "Hello";
f.s2 = "world";
Foo f2 = f;
assert(f2.s1 == "Hello");
assert(f2.s2 == "");
}
I saw some code that reconsruct Object on c++.
from GeeksForGeeks :
#include<iostream>
#include<string.h>
using namespace std;
class String
{
char *p;
int len;
public:
String(const char *a);
};
String::String(const char *a)
{
int length = strlen(a);
p = new char[length +1];
strcpy(p, a);
cout << "Constructor Called " << endl;
}
int main()
{
String s1("Geeks"); // line 1
const char *name = "forGeeks";
s1 = name; // line 3
return 0;
}
Now, after line 3 s1 is a different object?
I always thought that after you construct object, you can't dereference it.
What you see is an assignment.
A copy assignment operator is automatically generated in your class, since you don't define one yourself. From the page I linked to:
If no user-defined copy assignment operators are provided for a class
type (struct, class, or union), the compiler will always declare one
as an inline public member of the class.
There is actually no dereferencing on line 3: there is only a replacement of an object with an another. The line 3 calls the constructor of String and assign the object to s1. So two different instances of String are being created but the constructor is not ´recalled´ on the first object but assign the created one to s1. The operator = is used as its default behavior which is to find if there is a constructor that matches the type given to the = operator.
On a side note, the dynamic memory is not freed at any point in the code making it a bad code sample.
Let's break it down.
s1 = name;
First, the compiler will construct a new String object using the constructor String(char const*). Then it uses the copy assignment operator to update s1 with this newly created object.
Since you did not define this operator, it simply does a copy of the class members, i.e. p and len: that's the default implementation the compiler generates for you. The old object is not cleaned up before so you are leaking memory... You should thus write your copy semantics using the copy and swap idiom:
class String {
char *p;
int len;
public:
// Your constructors...
// Swap function
friend void swap(String& s1, String& s2) {
using std::swap;
swap(s1.p, s2.p);
swap(s1.len, s2.len);
}
String(String const& other) : p(new char[other.len]()), len(other.len) {
std::copy(other.p, other.p + len, p);
}
String& operator=(String other) {
swap(*this, other);
return *this;
}
// And finally, a destructor:
/* virtual */ ~String() {
delete [] p;
}
};
I read some sample code in the book C++ Primer:
I do not understand how the direct initialization of a pointer works in ps(new std::string(s)) and ps(new std::string(*p.ps)).
If ps is a pointer to string, then why is it ok to place a string as the parameter inside of its direct initialization constructor?
class HasPtr {
public:
HasPtr(const std::string &s = std::string()):
ps(new std::string(s)), i(0) { }
// each HasPtr has its own copy of the string to which ps points
HasPtr(const HasPtr &p):
ps(new std::string(*p.ps)), i(p.i) { }
HasPtr& operator=(const HasPtr &);
~HasPtr() { delete ps; }
private:
std::string *ps;
int i;
};
The new expression creates space for an std::string on the heap and returns a pointer to it. Hence, it is not a string that ps is initialized with, but a pointer to string, which ps is a type of.
HasPtr::ps is a std::string*.
If I dereference a std::string* like this *ps I get the actual std::string object.
If I have an object const HasPtr p I can get it's member pointer to std::string with: p.ps. This is only possible inside class HasPtr because ps is private.
If I do *p.ps I will get the std::string pointed to by p's member std::string*.
So the code:
HasPtr(const HasPtr &p):
ps(new std::string(*p.ps)), i(p.i) {}
Is using the std::string copy constructor to initialize the dynamically created std::string that will be assigned to this->ps by the HasPtr copy constructor.