Given the new C++11 standard and the move semantics introduced in it, could it be possible to create default values for constructor references? Here Default value to a parameter while passing by reference in C++ it is said that no, but perhaps the new standard allows some trickiness.
Basically what I want is to use a default object for the normal usage and to pass a mock object that records all the calls the host object has done in the testing phase. It should be something like
class A {
B& b;
public:
A(B & b = B()){} // This does not work
}
and when testing what I want is
BMock bMock;
A a(bMock);
bMock.getStatistics();
Any ideas?
How about this:
class Foo
{
B default_B;
public:
std::reference_wrapper<B> b;
Foo() : b(std::ref(default_B)) { }
Foo(B & br) b(std::ref(br)) { }
};
Here's an alternative idea that might be lighter-weight, at the expense of dynamic allocation in the default case:
#include <memory>
class Foo
{
std::unique_ptr<B> pB;
public:
std::reference_wrapper<B> b;
Foo() : pb(new B), b(std::ref(*pb)) { }
Foo(B & br) pb(), b(std::ref(br)) { }
};
Yes, the default initializer expression is a temporary object, and it will bind to an rvalue reference. However, you need to pass non-temporary objects through std::move to get them to bind to the reference.
Usually passing something through std::move indicates that it will be destroyed by the called function. The standard goes so far as to call the result of std::move an "expiring value;" although there's no real semantic necessity for it to expire, it's a pretty strong convention.
So, you can do this, but be careful.
Looking closer at your example, you want to keep a reference to b inside a, which means that there's nowhere to permanently store the proposed default value if no argument were used. You would be retaining a reference to a destroyed temporary. So unfortunately I can't really adapt your example…
Just an idea, what about this:
class A
{
std::shared_ptr<B> m_b;
public:
A() : m_b(new B) {}
A(B& b) : m_b(&b, [](B*){}) {}
};
On another note, I'm against storing off anything you take as a reference, I don't feel it connotes your usage at all. I'm also against members which are references, as they disallow assignment operators.
Related
I have a vector of class instances. Each of those instances has a unique_ptr to another class.
Since I never try to copy the class instance or even share the pointer, I felt like unique_ptr are more appropriate than shared_ptrs since the pointer is not shared, but only accessible through the class instance.
Is it bad practice? And why wouldn't this work? I understand that copying an instance to a unique pointer would be ill-formed, but since I move it, I do not understand why this would not be allowed?
Would I have to create a custom move constructor? And what should it do?
The unique ptr should be deleted as soon as the object instance is being removed from the vector as there are no references left, right?
Code Example for better understanding:
class A {
private:
int number;
public:
void f() {
std::cout << "The number is: " << number;
}
A(int i) : number{i} {}
~A() = default;
};
class B {
std::unique_ptr<A> good_a;
B() : good_a{ std::make_unique<A>(1) } {}
~B() = default;
};
int main()
{
std::vector<B> all;
B my_b(123);
all.emplace_back(std::move(my_b));
}
This answer focuses on compilation error you seem to be having. Bad or good practice is left for others to chime in.
Your code have several errors there, but the main one seems to be that your custom B( ) constructor inhibits default move constructor. If you add it, your code becomes well-formed.
Here is a full working code for the reference:
#include <memory>
#include <vector>
class A {
private:
int number;
public:
void f();
A(int i) : number{i} {}
~A() = default;
};
struct B {
std::unique_ptr<A> good_a;
B(int k) : good_a{ std::make_unique<A>(k) } {}
B(B&& ) = default;
B& operator=(B&& ) = default; // not needed for the example, but good for completeness
};
int main()
{
std::vector<B> all;
B my_b(123);
all.emplace_back(std::move(my_b));
}
And why wouldn't this work?
What you described could work.
I do not understand why this would not be allowed?
What you described would be allowed.
Would I have to create a custom move constructor?
No, that wouldn't be necessary, unless you define other special member functions, or have other members (beside the unique pointer) that have deleted or private move constructor.
The unique ptr should be deleted as soon as the object instance is being removed from the vector as there are no references left, right?
Members are destroyed when the super object is destroyed. And the destructor of the unique pointer invokes the deleter on its owned pointer.
Whether there are references to the pointed object has no effect on whether it is deleted or not. Anything referring to the deleted object will be left dangling.
Is it bad practice?
There isn't necessarily anything particularly bad about what you described in general, but that depends on exact details.
One potential issue is that dynamic allocation can be expensive in some cases, and using it unnecessarily would then be unnecessarily expensive. As such, you should to have some reason to allocate the pointed objects dynamically rather than storing them directly as members.
Bugs in your example:
You attempt to initialise B(123) but B has no constructor accepting an integer.
You attempt to initialise a B outside a member function of B, but its constructors and the destructor have private access.
You have user declared destructor for B, but no user declared move constructor or assignment operators and therefore the class isn't movable, which is a requirement for storing in std::vector.
Here is a fixed version that doesn't use unnecessary dynamic allocation:
struct A {
int number;
};
struct B {
A good_a;
};
B my_b{123};
all.push_back(my_b);
Please read this answear.
Depending what is explicitly declared respective constructors with default implementation are implicitly defined or dropped. Rules are described by this table:
Since you have used explicit defined destructor (as default) you have disabled ("not declared") move constructor.
So to fix it you have to explicitly define move constructor or remove definition of destructor: https://godbolt.org/z/dr8KrsTfq
Suppose I have a class A, the class is copyable, but it will take a lot to copy it.
Suppose I have a class B, it can return a const reference of A.
class B
{
public:
...
const A& obtainA() const
{
return a;
}
private:
A a;
};
When I want to use A from B, I think the best practice is accessed A in B by const reference
B b;
const A& a = b.obtainA(); // do not needs to the heavy copy operation of A, good.
However, I always forget the const reference, my code looks like follow.
B b;
A a = b.obtainA(); // leads to the heavy copy operation of A, not good
It not only leads to the heavy copy operation but also the unsafety.
If the a call the non-const member function by mistake, it will leads to the member a in b be changed out of class.
Is there exists any way can help me to return const reference?
I want something like, if not returned by reference, the code can not be compiled.
Or any other advice is OK.
Thanks for your time.
Concrete applications
A in my application is the shared array. The data stored in the array is shared, it just something like the std::shared_ptr, but manage array of object but not single object.
The array is designed can be shared to reduce the copy overhead. The A is copyable because the array should be copyable.
The array is a widely used class, thus it is often a member of Array's user, that is the B in this question.
You could make A non-copyable, and provide a method to do the copy explicitly.
class A {
private:
A(A const &); // expensive copy
public:
A make_copy() { return *this; }
};
The make_copy method will create the expensive copy, but other code will no be able to make copies implicitly, since the copy-constructor is private.
If you do not want an object to be modified, make the object itself constant:
B const b;
A a = b.obtainA(); // nope, not allowed
I personally believe that everything should be constant unless there is a good reason for it not to be.
I'm fairly new to Pass By Reference, and I HAVE to make sure I understand this correctly. I have to convert all my Heap memory to Stack memory because my professor said so, and I'm stuck on two concepts.
What is the best way to store a reference in a class? I originally had member objects as non pointers, but noticed the deconstructor would be called on the member variable when the object (not member object) was popped off the stack. This makes me think it was a copy, and not actually a reference.
Here is an example of what I had originally:
class B
{
public:
B();
~B();
};
class A
{
private:
B b;
public:
A();
~A();
setB(B& bVar);
};
void A::setB(B& bVar)
{
b = bVar;
}
My solution was to change it to a pointer so it didn't call the deconstructor, but I'M NOT SURE IF THIS IS THE CORRECT WAY TO DO IT. Here was my solution:
class B
{
public:
B();
~B();
};
class A
{
private:
B* b;
public:
A();
~A();
setB(B& bVar);
};
void A::setB(B& bVar)
{
b = &bVar;
}
My second question is kind of related. I'm not sure what exactly happens when you have:
object1 = object2&.
Is object1 a copy or is it actually another identifier for object2?
References behave like symbolic aliases to instances, and are in some respects like "pointers" that can't (shouldn't) be null. For the sake of this explanation, I'll refer to them below as though they were pointers.
When you have a T&, it means that it is pointing to a T, and is not itself a copy.
When you have a T = T&, it means you'll get a copy (or a copy of a copy) depending on how the constructor or assignment operator are defined.
When you have an R& = L, it means you'll get copy of L into whatever the R& is pointing to (provided the assignment operator of R permits this).
Concerning the "correct" way of storing references, I would ask at least these questions:
Is it acceptable for the member reference to remain the same throughout the containing object's lifetime?
Will instances of the containing type always be destroyed before the object(s) pointed to by the member reference?
If both are true, then simply declaring and appropriately initializing a member T& should suffice:
class B
{
// details...
};
class A
{
B &_b;
public:
A(B &b) :
_b(b)
{}
};
Otherwise, despite the requirements imposed upon you, the situation might call for something like shared_ptr<> or similar.
References to objects living on the stack, in-turn held by other objects that themselves may be constructed in such a way that they will outlive their reference's lifespan are merely pointers waiting to dangle.
Consider copying, or arguing that heap-allocated memory is the better option.
If you are uncertain of the reference network induced by your program, you need to redesign it.
EDIT:
It is important to note that, when passing a reference to a function (const T& in particular), there are certain situations in which it can be elided by the compiler. For example: When such a function is inlined, references can be replaced by more efficient addressing logic than if they were required to be pointers.
In this respect, they are not pointers.
Say, i have a function which returns a reference and i want to make sure that the caller only gets it as a reference and should not receive it as a copy.
Is this possible in C++?
In order to be more clear. I have a class like this.
class A
{
private:
std::vector<int> m_value;
A(A& a){ m_value = a.m_value; }
public:
A() {}
std::vector<int>& get_value() { return m_value; }
};
int main()
{
A a;
std::vector<int> x = a.get_value();
x.push_back(-1);
std::vector<int>& y = a.get_value();
std::cout << y.size();
return 0;
}
Thanks,
Gokul.
You can do what you want for your own classes by making the class non copyable.
You can make an class non copyable by putting the copy constructor and operator= as private or protected members.
class C
{
private:
C(const C& other);
const C& operator=(const C&);
};
There is a good example of making a NonCopyable class here that you can derive from for your own types.
If you are using boost you can also use boost::noncopyable.
Alt solution:
Another solution is to have a void return type and make the caller pass their variable by reference. That way no copy will be made as you're getting a reference to the caller's object.
If your function returns a reference to an object that shouldn't have been copied, then your function already has done what it could do to prevent copying. If someone else calls your function and copies the return value, then either
it's an error the caller made, because the object should never be copied (in which case the return type probably shouldn't have been copyable in the first place), or
it's irrelevant for the caller because the function is only called once in a week (in which case you must not try to cripple your callers' code), or
it's a pretty dumb oversight on the side of the caller (in which case the error will be found by profiling).
For #1, either you return have your own type or you can wrap whatever your return in your own type. Note that the only difference between #2 and #3 is the relevance - and if it's relevant, profiling will find it.
IMO you should not cripple your code by returning a pointer when what you need is a reference. Experienced programmers, seeing the pointer, will immediately ask whether they need to check for a NULL return value, whether the object is allocated dynamically and, if so, who is responsible for cleaning it up.
You should also not blindly forbid copying of whatever you return, if you cannot eliminate the possibility that copying is needed.
In the end it's the old motto, which C++ inherited from C: Trust your users to know what they are doing.
It "depends". Yes, you can hide the copy-constructor (and assignment operator), and your object becomes noncopyable:
struct foo
{
private:
foo(const foo&); // dont define
foo& operator=(const foo&); // dont define
}:
But if you're wondering about one specific function (i.e., normally copyable, but not for this function), no. In fact, what can you do about the caller anyway?
const foo& f = get_foo(); // okay, by reference, but...
foo f2 = foo(foo(foo(foo(foo(foo(f)))))); // :[
If your caller wants to do something, there isn't much you can do to stop it.
In C++11, you can prevent the copy constructor from being called by deleting it:
class A{
public:
A(const A&) = delete;
}
Are you trying to prevent a common typo that causes large objects to accidentally be copied? If so, you could return by pointer instead. Leaving off an & is pretty easy, but it takes a little bit of effort to copy an object from a pointer. OTOH, the resulting code will be uglier, so it's up to you whether it's worth it.
I have some library code (I cannot not change the source code) that returns a pointer to an object (B). I would like to store this pointer as shared_ptr under a class with this type of constructor:
class A
{
public:
A(boost::shared_ptr<B> val);
...
private:
boost::shared_ptr<B> _val;
...
};
int main()
{
B *b = SomeLib();
A a(b); //??
delete b;
...
}
That is, I would like to make a deep-copy of b and control its life-time under a (even if original b is deleted (delete b), I still have an exact copy under a).
I'm new to this, sorry if it seems trivial...
If the library defines this B object, the library should provide (or outright prohibit) the mechanism for copying B.
As a sidenote,
If your class A is exclusively controlling the lifetime of this copied object, the smart pointer you really want to use is boost::scoped_ptr.
boost::shared_ptr is named after its ability to share lifetime responsibility, which it sounds like you don't want. scoped_ptr won't let that accidentally happen.
As you say, you have to copy them not just copy a pointer. So either B already has implemented 'clone' method or you have to implement some external B* copy(B* b) which will create new B with same state.
In case B has implemented copy constructor you can implement copy as just
B* copyOf(B* b)
{
return new B(*b);
}
In case B has implemented clone method or similar you can implement copy as
B* copyOf(B* b)
{
return b->clone();
}
and then your code will look like
int main()
{
B *b = SomeLib();
A a(copyOf(b));
delete b;
...
}
Deep-copying is implemented trivially in C++ by the copy constructor since in C++, all objects have value semantics by default. Copying in such a way doesn't work for polymorphous objects though – in such cases, you'd have to implement a virtually overridden clone method in your class.
But in all other cases, simply writing
A(boost::shared_ptr<B> val) : _val(new B(*val)) { }
will do.