C++11 usage of delete specifier vs private functions - c++

I am in the process of boning up on my C++ (as in, attempting to get into more modern-style coding) and am looking at the delete specifier. It is my understanding that it is used to make sure that certain functionality cannot be defined or called. If I understand it correctly, this is primarily within the domain of assignment and copy. I am not quite sure what the difference is between using the delete specifier and just making those functions private.
For instance, what is the difference between:
class Foo {
private:
Foo& operator(const Foo&);
Foo(const Foo&);
};
And
class Bar {
public:
Bar& operator(const Bar&) = delete;
Bar(const Bar&) = delete;
};
In other words: what does using the delete specifier gain? Is it just to make things look nicer?

One obvious difference is that if you make the function private, then it is still accessible from within the class and any friends.
An explicitly deleted function is not usable anywhere, so you know simply from that one line that it's never used, without having to inspect the implementation.
You can make the function both private and deleted: then its participation in overload resolution is more consistent.

It's simpler.
This way, your intent is clearly stated and your compiler can outright say "calling this function is prohibited".
Otherwise you're relying on:
access control (for attempted calls from outside of the class), or
the linker giving you an "undefined reference" near the end of your build process. That's kind of okay for small programs where you can quickly find out what's going on, but for deep class hierarchies where some many-times-over encapsulated object cannot be copied but has not been deleted, good luck debugging that.

Short answer is: uses of a deleted function make the program ill-formed and you are notified at compile-time, uses of a function that is not defined end in an odd error that comes out of the linker.
As an example, there is a relevant part of the standard that states:
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed.
Therefore, the following compiles just fine:
struct S {
void f();
};
template<typename T, void (T::*M)() = &T::f>
void g() {}
int main() {
g<S>();
}
While the code below does not:
struct S {
void f() = delete;
};
template<typename T, void (T::*M)() = &T::f>
void g() {}
int main() {
g<S>();
}
That's because in the second case the code is ill-formed and you have a compile-time error in any case, no matter if you are going to use or not M. In the second case, you get an error out of the linker only if you try to use it:
template<typename T, void (T::*M)() = &T::f>
void g() {
T t;
(t.*M)();
}
Of course, compile-time errors are much better to prevent issues. The example uses public functions, but making them private doesn't prevent from using them within the class in similar ways. That's just a toy example to show a possible difference.

Related

Initialization of inner private class within public constructor call of outer class -What's the standard's intention for this?

Recently, I came across code like this:
class NeedsFactoryForPublicCreation
{
private:
struct Accessor
{
// Enable in order to make the compile failing (expected behavior)
// explicit Accessor() = default;
};
public:
explicit NeedsFactoryForPublicCreation(Accessor) {}
// This was intended to be the only public construction way
static NeedsFactoryForPublicCreation create()
{
NeedsFactoryForPublicCreation result{Accessor()};
// ... Do something (complex parametrization) further on
return result;
}
};
int main()
{
//NeedsFactoryForPublicCreation::Accessor publicAccessor {}; // Does not compile as expected
NeedsFactoryForPublicCreation nonDefaultConstructible {{}}; // Compiles even with Accessor being an interal
}
At first, I was a bit shocked, that this compiles.
After some minutes of analysis (and occurring self-doubts...), I found out, that this is fully explainable due to the definition of access specifiers and the way the compiler decides what actual way of initialization is used (aggregate vs. public constructor look-up). In order to extend the first confusion, even this access class compiles this way:
class Accessor
{
Accessor() = default; // private, but we are an aggregate...
friend class NeedsFactoryForPublicCreation;
};
which is again fully explainable since Accessor is still an aggregate (another confusing topic...).
But in order to emphasize, that this question has nothing to do with aggregates in detail (thanks to Jarod42 in the comments to point out the upcoming C++20 changes here!), this compiles too:
class Accessor
{
public:
Accessor() {}
virtual ~Accessor() {}
virtual void enSureNonAggregate() const {}
friend class NeedsFactoryForPublicCreation;
};
and does not as soon as the constructor becomes private.
My question: What's the actual background, the standard decided the effect of access specifiers this counterintuitively in doubt? With counterintuitively I especially mean the inconsistency of effective look-up (the compiler doesn't care about the internal as long as we stay unnamed, but then cares when it comes to actual constructor look-up, still fully unnamed context). Or maybe I'm mixing categories too much here.
I know, access specifiers' background is quite strictly naming based and there are also other ways to achieve the "publication" of this internal, but as far as I know, they are far more explicit. Legally implicitly creating an unnamed temporary of a private internal within an outer scope via this extremely implicit way looks horrible and might even be quite error prone, at latest when multiple arguments are the case (uniform initialized empty std-containers...).

this->field vs. this.field in C++

How do lines (2) and (3) even compile in the following C++ class, given that this is a pointer, so should need -> notation to access fields (as seen in line (1))? (Source)
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
template <typename T>
class sptr_wrapper
{
private:
boost::shared_ptr<T> sptr;
public:
template <typename ...ARGS>
explicit sptr_wrapper(ARGS... a)
{
this->sptr = boost::make_shared<T>(a...);
}
explicit sptr_wrapper(boost::shared_ptr<T> sptr)
{
this->sptr = sptr; // (1)
}
virtual ~sptr_wrapper() noexcept = default;
void set_from_sptr(boost::shared_ptr<T> sptr)
{
this.sptr = sptr; // (2)
}
boost::shared_ptr<T> get_sptr() const
{
return sptr; // (3)
}
};
The line (2) is invalid. As you said, this is a pointer, we need to use -> instead of .
As the member of class template, sptr_wrapper::set_from_sptr is not required to be instantiated, until it's used. So you can add some code trying to call it, then you might get compile-errors as you expect.
This applies to the members of the class template: unless the member is used in the program, it is not instantiated, and does not require a definition.
The line (3) is valid; sptr refers to the member sptr, which has the same effect as this->sptr.
When a non-static class member is used in any of the contexts where the this keyword is allowed (non-static member function bodies, member initializer lists, default member initializers), the implicit this-> is automatically added before the name, resulting in a member access expression (which, if the member is a virtual member function, results in a virtual function call).
Would you believe that the reason this compiles is because nothing really gets compiled here?
The shown code defines a template.
A template does not become "real" until it instantiates a class. Only at that time the compiler gets a closer look at the template, and attempts to figure WTF it's doing.
Sure, when defining a template the compiler makes a half-hearted attempt to parse the template, but only barely enough to satisfy itself that the template consists of some plausibly-looking C++ code.
If you add some additional lines to the shown code you'll get the compilation errors you were yearning for:
class X {};
void foo()
{
sptr_wrapper<X> x;
boost::shared_ptr<X> y;
x.set_from_sptr(y);
}
And this produces the compilation errors you were looking for:
t.C:27:14: error: request for member ‘sptr’ in ‘(sptr_wrapper<X>*)this’, which is of pointer type ‘sptr_wrapper<X>*’ (maybe you meant to use ‘->’ ?)
27 | this.sptr = sptr; // (2)
Note that merely instantiating
sptr_wrapper<X> x;
isn't enough. You have to go full throttle and invoke the method in question, before it becomes "real" in the eyes of a C++ compiler, and it chokes on it.
It's true that I can quite think of any circumstance where "this.foo" might be valid C++ code, but I'm sure that somewhere in the 2000 pages that make up the current C++ standard, the exact details of what's going on gets spelled out in a very pedantic way.
And you might consider dropping a note to your compiler's bug tracker, a feature request to have your compiler issue a friendly warning, in advance, when it sees something like this.

Reference qualifiers and deleted member methods

Consider the following code:
#include<utility>
struct S {
void f(int) = delete;
void f(int) && { }
};
int main() { }
It doesn't compile saying that the member method cannot be overloaded and it makes sense, of course.
On the other side, the following code compiles:
#include<utility>
struct S {
void f(int) & = delete;
void f(int) && { }
};
int main() {
S s;
// s.f(42); <-- error, deleted member method
std::move(s).f(42);
}
Is that legal code?
Wouldn't it be possible to define two completely different interfaces within the same class, the former to be used with lvalues, the latter with rvalues?
Apart from the fact that it doesn't make much sense, but it really hurts me.
Shouldn't a deleted function be deleted as a whole, instead of deleted only if you are a lvalue?
Which is the purpose of this feature? Is it the classic obscure corner case or is there something more I can't see?
Sometimes it makes sense to prohibit certain operations if object is l- or r-value.
Imagine RAII wrapper for FILE*. It opens file in constructor, closes it in destructor, turning C feature requiring manual control to C++ exception-safe class. To interact with C interface, there is a .get() member which returns raw pointer. Someone might write:
FILE* file = CFile("file.txt").get();
It would compile, but it is wrong: file would be closed as soon, as file variable would be initialized. If you delete an r-value overload (on never provide it in the first place), then it would lead to compile-time error and save us from bug-hunting.

C++ facade avoiding copies

Consider the following, simplified facade pattern:
class Foo {
public:
int times;
int eval(const int val) { return val*times; }
};
class Bar {
Foo foo;
public:
Bar(const Foo& f) : foo(f) {}
double eval(const double val) { return val * foo.times; }
};
Obviously, an instance of Bar is only required to evaluate a special (i.e. double-valued) interpretation of Foo's eval() method. A Bar won't have any other members except the foo it forwards to.
For safety reasons I have not used a const reference or a pointer inside Bar (I just don't know yet if at some point a Bar instance might escape from a stack frame, so resource management is important).
My question here is two fold:
Can the C++ compiler possibly detect that Bar is merely a facade and
"inline" the member access?
Is there a (safe) way to prevent copying
of the passed object?
On some platforms (gcc/clang) you can force inlining with the attribute always_inline or emit warnings should a function not be inlined.
No, if you don't want to copy, you need to guarantee the life-time of the object elsewhere. If you consider this to be unsafe, don't do it. What you can do is move an object. This avoids copies and life-time issues, but might not be possible with your compiler.
For example:
struct Bar {
// Only accept rvalues of Foo
explicit Bar(Foo&& f) : f(std::move(f)) {}
Foo f;
};
1- Yes, the compiler will most probably inline the function [It depends on compiler).
2- Always stick to RAII. In C++3, Foo object foo shall be either member variable (as you did), or managed pointer (copied at copy constructor and assignment operator and deleted at destructor). In C++11 you can use right value reference.
NOTE: This example is not a facade!

Why doesn't C++ cast to const when a const method is public and the non-const one is protected?

I created a class with two get methods, one const and one non-const. The const method is public, so users can query the vector. The non-const method is protected, so I can use it to modify the data I need.
When I try to use the class, however, and call the get method, the compiler complains that the non-const method is protected. Instead, I have to use const_cast to cast the object to const, so I can get instead the public method.
Is there a way to solve this? Why wouldn't the compiler do the cast itself, since there is a public method? If I remove the protected version and just leave the const one, it works fine, so it does do the cast in this situation. Casting to const is always safe. It's removing constness that is a problem.
Member access control is the very last thing that occurs when calling a member function. It happens after name lookup, template argument deduction, overload resolution, and so on. The reason why it is done last is because it was decided that changing the access control for a member should not suddenly change the execution of client code.
Imagine access was checked before overload resolution, and you used a library and a certain member function in that library. Then the library authors made the function private. Suddenly, your code starts using a different overload and behaves in a completely different way. The library authors probably intended that anybody using that overload of the function should stop using it, but they didn't intend to change everybody's code. However, as the standard is actually defined, your code would now start giving you an error for using a private member, rather than behave differently.
The solution is to simply change the name of your protected member function so that it isn't considered.
The compiler considers accessibility after it decides what member function it wants to call. That is, protected and private functions are still visible, even though they aren't accessible.
Why? One reason is that if you made inaccessible functions ignored by overload resolution, you could change what function is called simply by changing its accessibility. With the current rules, you can only cause compiling code to fail to compile, or cause code that currently doesn't work to compile, or change something with no effect on the meaning of the code. You cannot change access specifiers and silently cause a different function to be called.
As a contrived example, here's a pretty terrible class interface:
public:
// Returns the amount of change tendered for this transaction.
MoneyAmount change() const;
private:
// Account for a change of currency. Charges standard moneychanger's fee.
MoneyAmount change(Currency toCurrency = Currency::USD);
If inaccessible functions were removed from overload resolution, client code could call change() just fine. And if later the second change(Currency) function was made public and the first one deleted, that code would suddenly silently call another function with an entirely different purpose. The current rules prevent a change of access specifier from changing the behavior of a compiling program.
In C++, method selection (overloading resolution) happens before considering public/private access control.
Use a protected setter method instead (or data member) instead of the non const getter method.
It makes no difference if you have s.th. like
class A {
SomeType foo_;
protected:
SomeType& foo() { return foo_; }
public:
const SomeType& foo() const { return foo_; }
};
or
class A {
protected:
SomeType foo_;
public:
const SomeType& foo() const { return foo_; }
};
That is the nature behavior of C++, if the caller code the object of the class is non-const so the non-conversion, which is defined as protected one. You need defined the object of class as const or use const-cast on the object of the class, which will result that the const version of the method will be called.
#include <iostream>
class Foo {
public:
const void bar() const { std::cout << " const version called\n";}
protected:
void bar() { std::cout << " non const version called\n";}
};
int main(int argc, char** argv)
{
const Foo c;
c.bar(); // -> work
Foo c1;
c1.bar(); // compiler complain -> void Foo::bar() is protected
const_cast<const Foo&>(c1).bar(); // fine
}