Given code like the following:
void f()
{
int i;
i = 0;
}
is it possible the system could throw an exception due to the simple assignment?
[Edit: For Those saying, "No an exception cannot occur," can You point Me in the direction of the part of the C++ standard which says this? I am having trouble finding it.]
Although you'd probably be hard put to find an assurance of it in the standard, a simple rule of thumb is that anything that's legitimate in C probably can't throw. [Edit: The closest I'm aware of to a direct statement to this effect is at §15/2, which says that:
Code that executes a throw-expression is said to “throw an exception;” [...]
Looking at that in reverse, code that does not execute a throw-expression does not throw an exception.]
Throwing is basically restricted to two possibilities: the first is invoking UB. The second is doing something unique to C++, such as assigning to a user-defined type which overloads operator =, or using a new expression.
Edit: As far as an assignment goes, there are quite a few ways it can throw. Obviously, throwing in the assignment operator itself would do it, but there are a fair number of others. Just for example, if the source type doesn't match the target type, you might get a conversion via a cast operator in the source or a constructor in the target -- either of which might throw.
There's quite a lot of things that look like assignments that can throw one way or another:
int operator"" _t(const char *) { throw 0; } // C++11 user defined literal
struct foo {
foo(int) { throw 0; }
operator int() { throw 0; }
foo& operator=(int) { throw 0; }
};
int main() {
int i;
i = 0; // can't throw
i = 0_t; // User defined literal throws
foo f = 0; // Constructor throws
i = f; // conversion operator throws
f = 0; // assignment throws
f = f; // both conversion and assignment would like to throw
}
(including the new one from C++11)
If you're concerned about assinging 0 (which has type int) to an
int, §5.17 of the standard specifies very exactly the semantics of the
assignment operation, and there is no case where an exception can occur.
If you're concerned about assigning an arbitrary expression to an int,
§5.17 says that “the expression is implicitly converted to the
cv-unqualified type of the left operand." Depending on the actual type
of the right operand:
If it is an integral type, if the actual value cannot be represented in an int, the results are implementation defined (the C standard is more explicit: it must either result in an int with an implementation defined value, or you will get an implementation defined signal)
If it is a floating point value, the result is undefined behavior if the value after truncation to zero cannot be represented in an int, the behavior is undefined (so you might get an exception)
If it is a user defined type, then a user defined conversion operator will be called. Which can throw an exception.
If you're concerned about assigning other types: for each set of
non-class types, there is a list of rules like the above, but the only
possible exceptions will be as a result of a type conversion. For class
types, the operator= will be used. Which can throw an exception,
depending on what is in it.
It can throw an exception only in one case: when overloaded operator=() for those two types throws; similary, when conversion is needed, the converting constructor or operator T() can also throw. It depends on the exact implementation then - to find out if it will throw, look for information about it in documentation of library you are using.
if it's just an int, then no - it will not throw.
if it's something more complex, such as a vector, then it may throw for a number of reasons (e.g. allocation failure or alteration from a secondary thread).
Related
I understand the value of keyword explicit when used in cases where there is a chance of creating ambiguity, like the examples I am seeing here and here.
Which I understand as prevents implicit conversion of basic types to object type, and this makes sense.
struct point {explicit point(int x, int y = 0);
};
point p2 = 10; // Error: would be OK without explicit
What I want to understand is what value explicit brings when I am using custom datatypes as constructor argument?
struct X {X(int x);}; // a sample custom datatype I am referring to.
struct pointA { pointA(X x);}; // here this looks to me same as
struct pointB {explicit pointB(X x);}; // like here this
int main() {
pointA pa = 10; // fails as expected
return 0;
}
The point of explicit has nothing to do with the parameter list, it has to do with the type being constructed, especially if there are side-effects. For example, consider std::ofstream.
void foo(std::ofstream out_file);
// ...
foo("some_file.txt");
Without explicit, this will attempt to open some_file.txt and overwrite its contents. Maybe this is what you want, but it's a pretty big side-effect that's not obvious at the calling point. However, consider what we'd have to do since the relevant std::ofstream constructor is explicit.
foo(std::ofstream("some_file.txt"));
It's far more clear, and the caller isn't surprised (or at least shouldn't be).
Whether the type being constructed is built-in, from a third-party library, or something you wrote yourself: it's irrelevant. explicit is useful anytime you don't want a type to be constructed without somebody being very explicit (hence the keyword) that's their intention.
The value that explicit brings when custom data types are used as constructor argument is the same as the value when basic types are used as the argument.
That really should be the end of the answer, as trying to draw a distinction between these cases is inventing a complication that does not exist. However, the OP does not accept this and has declined to clarify why this is even a question. So to give this answer content, I will show why the question fails to demonstrate a distinction. Then I will return to the nominal question and demonstrate one way in which explicit has value, regardless of the type of the constructor's argument.
Implicit conversion sequences
The question shows a case where constructing a pointA object from an int fails, but this failure has nothing to do with whether the conversion is explicit or implicit. It cannot, since both pointA and X have implicit constructors. There is no way for the explicit specifier to come into play. The second code block in the question has no value in the context of the question. Rather than jumping to the conclusion that explicit has no value, the OP should have questioned why the conversion failed. The OP asked the wrong question, but we are stuck with it.
What the code in the question demonstrates is that an implicit conversion can use at most one user-defined conversion. Converting an int to an X is one user-defined conversion. Converting an X to a pointA is a second user-defined conversion. You cannot use both in a single implicit conversion. Hence, the failure of the question's pointA pa = 10;.
A more appropriate code example
To get a situation comparable to the first code block in the question, one should initialize with values of type X instead of those of type int. Since the first code block uses literals, let's start by looking at that case. (This is a little more complicated than the built-in case, since built-in types have built-in literals, whereas custom types do not. We'll need a user-defined literal.)
// X, pointA, and pointB defined as in the question.
// User-defined literal X
X operator ""_X (unsigned long long i) { return static_cast<int>(i); }
// Now use an X literal in the sample code instead of an int literal.
int main()
{
pointA pa = 10_X; // OK
//pointB pb = 10_X; // error: conversion from 'X' to non-scalar type 'pointB' requested
}
Here we use only one user-defined conversion, so an implicit conversion is possible as long as the user-defined conversion is not explicit. The constructor of pointB taking an X parameter is marked explicit, so that line fails to compile. In contrast, the pointA line succeeds, just like the case where the literal was a basic type. There is no distinction here, despite the OP's attempt to invent one.
If you don't like user-defined literals (or even if you do), you can get equivalent results by explicitly calling the user-defined conversion to X, as in
pointA pa = X{10}; // Succeeds
//pointB pb = X{10}; // Fails
Again, the effect of marking one constructor explicit is seen.
Leveraging explicit
Time to return the the nominal question being asked. What is the value of the explicit specifier? One benefit is avoiding expensive constructions. If pointA makes a shallow copy of the data in X, while pointB makes a deep copy, there could be good reason to avoid creating pointB objects unless that is explicitly requested. Again, it does not matter whether the parameter is of basic type or of user-defined type.
The question uses variable initialization as one example of this value. I find that a weak example, as changing point p2 = 10; to the more compact point p2{10}; allows the initialization. Those who have adopted the more compact style would not notice a difference due to marking the constructor explicit. There is little value of explicit here. The OP chose a poor example to demonstrate the value of explicit.
One of the better ways to demonstrate the value of explicit utilizes function parameters and function overloading. Consider a function that has been overloaded to accept either a pointA or a pointB parameter.
void fun(const pointA &) { std::cout << "fun(pointA)\n"; }
void fun(const pointB &) { std::cout << "fun(pointB)\n"; }
Let's go with the assumption that pointA is a cheap "view" of an X object, while pointB is an expensive copy. If we have an X object to use as a parameter, we would want to convert it to a pointA for this function. And that is exactly what happens.
int main() {
X test{0}; // Assume we have this object from somewhere.
fun(test); // Converts `test` to `pointA` and calls that overload.
// The overload taking a `pointB` is not called.
}
Both overloads are candidate functions in overload resolution. However, the version taking a pointB parameter is not viable because there is no implicit conversion from X to pointB. Hence, that version is dropped from consideration, leaving only the version taking a pointA parameter.
This demonstrates some of the value of marking constructors explicit. Expensive copies can be avoided, without the programmer having to think about it. In this case, not only is a potential ambiguity avoided, but also it is avoided by automatically choosing the more efficient overload.
Furthermore, this example would remain equally valid if each occurrence of X was replaced by int. The distinction between "basic types" and "custom datatypes" is a figment of the OP's imagination. Don't buy into it.
All C++ operators that I have worked with return something, for example the + operator returns the result of the addition.
Do all C++ operators return something, or are there some C++ operators that do not return anything?
No, not all operators return something.
Although they are probably not exactly what you are thinking about, note that the delete and delete[] C++ 'keywords' are actually operators; and they are defined as having the void return type - which means they evaluate to nothing (which is not 'something').
From cppreference:
void operator delete ( void* ptr ) noexcept;
void operator delete[]( void* ptr ) noexcept;
Operators of custom types can be overloaded to do the most weirdest things.
for example the + operator returns the result of the addition.
Not necessarily:
#include <iostream>
struct foo {
int value = 0;
void operator+(int x) {
value += x;
}
};
int main () {
foo f;
f + 3;
}
Here operator+ adds the left hand side to the value member, and its return type is void. This is a made-up example, but, in general, not returning something from a custom operator is not unusual.
The only operator that can be overloaded and that has the requirement of returning something, that I am aware of, is operator->. It must either return a raw pointer or an object that has an operator->.
To nitpick, operators don't return anything. They are just lexical elements that we use to create expressions in the language. Now, expressions have types and may evaluate to values, and I assume this is what you mean by operators "returning things".
And, well, yes. There are C++ expressions with type void (and consequentially don't evaluate to any value). Some are obvious, others less so. A nice example would be
throw std::runtime_error()
throw is an expression under the C++ grammar. You can use it in other expressions, for instance in the conditional expression
return goodStatus() ? getValue() : throw std::runtime_error();
And the type of a throw expression, is void. Obviously since this just causes execution to rapidly go elsewhere, the expression has no value.
None of the built-in C++ operators return something. Overloaded C++ operators return something insofar that the operator notation is a syntactic sugar for a function call.
Rather, operators all evaluate to something. That something has a well-defined value as well as a type. Even the function call operator void operator()(/*params*/) is a void type.
For example, +'a' is an int type with the value of 'a' encoded on your platform.
If your question is "Can C++ operators have a void return type?" then the answer is most certainly yes.
You can actually define a function call operator to return nothing. For example:
struct Task {
void operator()() const;
};
operator void(): user defined conversion function to void
You may define the peculiar operator void() conversion function, where the compiler will even warn you that the T to void conversion function will never be used:
#include <iostream>
struct Foo {
operator void() { std::cout << "Foo::operator void()!"; }
// warning: conversion function converting 'Foo' to
// 'void' will never be used
};
int main() {
Foo f;
(void)f; // nothing
f.operator void(); // Foo::operator void()!
}
as governed by [class.conv.fct]/1
[...] A conversion function is never used to convert a (possibly
cv-qualified) object to the (possibly cv-qualified) same object
type (or a reference to it), to a (possibly cv-qualified) base class
of that type (or a reference to it), or to (possibly cv-qualified)
void.117
(117)
These conversions are considered as standard conversions for the
purposes of overload resolution ([over.best.ics], [over.ics.ref]) and
therefore initialization ([dcl.init]) and explicit casts. A
conversion to void does not invoke any conversion function
([expr.static.cast]). Even though never directly called to perform a
conversion, such conversion functions can be declared and can
potentially be reached through a call to a virtual conversion function
in a base class.
Whilst, however, as is shown above, you can still invoke it using the explicit .operator void() syntax.
The operators defined (builtin) by the language are tokens used to perform different kinds of computations:
arithmetic (+,-,*,/)
increment/decrement (++,--)
assignment (=,+=,-=,*=,/=,%=,>>=,<<=,&=,^=,|=)
logic (!,&&,||)
relational (==,!=,>,<,>=,<=)
conditional ?
comma
and so on. The list can be very extensive.
In language references like this one or this one, these are not necessarily referenced as returning something, just performing an arithmetic or logic operation, a comparison by which means a variable may be modified, etc.
Since this operation results in some value, it may be interpreted as been "returned" by the operator, but it is different from a function return value.
The overloaded operators, on the other hand, can be defined with a return value of some type, even that can be void, so, no, not all operators return some value in C++.
I'm assuming you're talking about operator functions and not operators as a syntactic unit of the language.
If you overload operators on any type, you may actually return whatever you want.
This also makes a lot of sense, because operations like * or () may sometimes very intuitively not return their input type. Imagine multiplying a complex number type with a real number type. Or an operator that returns an element from a collection.
You may also overload the ++ and -- operators to not return anything thus removing the extremely error-prone mixing of side-effect and expression value that the standard version has.
No.
Consider these two examples here:
int multiply (int a, int b) {
return a*b;
}
void multiply_void(int a, int b) {
cout << a*b;
//or cout << multiply(a,b);
}
First function will return an integer value which can be used by another function.
The value is returned and stored in memory to be used when necessary. If not, it is not visible to human & just sits happily in the memory.
Second function will output to the default output device(usually console).
The value returned by the multiplication operator is passed to an output device.
The function multiply_void does not return an actual value.
All operators return something. They are called operators because they operate something , therefore they will return something. Those Operators who do not return something cant be called operators. Either they will return some value or return True or False depending upon the situation.
Operators on their own do not necessarily return anything. Function calls return values. Operators can result in values.
Operators can sometimes invoke functions. Examples include:
• The function call operator.
• An overloaded operator that gets transformed into a function call.
• operator new, which is invoked as part of a new-expression, is a function call.
My only purpose in mentioning function calls is to clarify the result vs. return. Based on looking at all 126 instances of “return” and words derived from it in [expr], the section seems to carefully use the word return to refer to:
• the result of a function call
• aspects of control flow related to coroutines
OK, that’s enough pedantry on result vs. return.
C++ Operators return something or not is depends upon how you used them. Built-In C++ operators return some value until and unless enforced to return void.
Think in a similar fashion like:
1. The bare name of an array is equivalent with the pointer to the first element, without the need to specify index 0.
2. toString() from Java makes it possible to use the name of an object as a string without calling any object method.
Now is there a way in C++ to use the name of a class object to refer to its first member?
Consider:
class Program
{
public:
int id;
char *str;
};
void function(int p)
{
//...
}
and then:
Program prog0;
function(prog0); // instead of function(prog0.id)
Any way to "hide" the member reference?
EDIT:
Why was the holyBlackCat's answer deleted? I was inclining to vote it as the best answer -- no offense, Mateusz. But he was the first to suggest conversion operator and the example was complete and simple.
In C++, such behaviour would be a cataclysm. If I understand correctly, Java tries to convert object of type A to object of type B by searching for first member in A, that is of type B or is implicitly convertible to B.
C++ wasn't designed that way. We like to write code, that is always predictable. You can achieve what you want, but for a price.
The best solution in this case would be conversion operator - consider:
class Program
{
public:
int id;
char *str;
operator int()
{
return this->id;
}
//You can have more than one!
operator const char*()
{
return this->str;
}
};
void function_int(int p)
{
}
void function_str(const char* s)
{
}
Now it is possible to do the following:
Program prog;
function_int(prog); //Equivalent of function_int(prog.id)
function_str(prog); //Equivalent of function_int(prog.str)
The price is, that if you add another int and place it before id it will not be used in conversion, because we stated in our operator explicitly, that "int content" of our class is represented by id and this member is considered when it comes to such conversion.
However, even this simple example shows some potential problems - overloading functions with integral and pointer types could result in very unpredictable behavior. When type contains conversion operators to both pointers and integers, it can get even worse.
Assume, that we have following function:
void func(unsigned long)
{
}
And we call func with argument of type Program. Which conversion operator would you expect to be called? Compiler knows how to convert Program to either int or const char*, but not unsigned long. This article on cppreference should help you to understand how implicit conversions work.
Also, as Barry pointed out, more meaningless constructs become available. Consider this one:
int x = prog + 2
What does it mean? It is perfectly valid code, though. That is why conversion operators should be dosed extremely carefully (in pre-C++11 era, there was a general advise, that every class should have at most one such operator).
Quote from MSDN:
If a conversion is required that causes an ambiguity, an error is generated. Ambiguities arise when more than one user-defined conversion is available or when a user-defined conversion and a built-in conversion exist.
Sometimes, simple solution to this problem is to mark conversion operator with explicit keyword, so you would need to change above calls to:
function_int((int)prog);
function_str((const char*)prog);
It is not as pretty as the previous form, but much safer. It basically means, that compiler is forbidden to perform any implicit conversion using operator marked as explicit. Very useful to avoid ambiguous calls, while still providing some flexibility in code - you can still very easily convert objects of one type to another, but you can be sure when and where these conversions are performed.
However, explicit conversion operators are still not supported by some compilers, as this is C++ 11 feature (for example, Visual C++ 11 doesn't support it).
You can read more about explicit keyword here.
Now is there a way in C++ to use the name of a class object to refer to its first member?
No, C++ doesn't have any reflection, so there's no way to actually determine what the "first member" is.
However, if what you really want is to get an ID for any object, you could just require that object to have that method:
template <typename T>
void function(const T& t) {
int id = t.getID();
// etc.
}
Without knowing more about your use-case, it's hard to know what to propose.
In one of the projects I'm working on, I'm seeing this code
struct Base {
virtual ~Base() { }
};
struct ClassX {
bool isHoldingDerivedObj() const {
return typeid(1 ? *m_basePtr : *m_basePtr) == typeid(Derived);
}
Base *m_basePtr;
};
I have never seen typeid used like that. Why does it do that weird dance with ?:, instead of just doing typeid(*m_basePtr)? Could there be any reason? Base is a polymorphic class (with a virtual destructor).
EDIT: At another place of this code, I'm seeing this and it appears to be equivalently "superfluous"
template<typename T> T &nonnull(T &t) { return t; }
struct ClassY {
bool isHoldingDerivedObj() const {
return typeid(nonnull(*m_basePtr)) == typeid(Derived);
}
Base *m_basePtr;
};
I think it is an optimisation! A little known and rarely (you could say "never") used feature of typeid is that a null dereference of the argument of typeid throws an exception instead of the usual UB.
What? Are you serious? Are you drunk?
Indeed. Yes. No.
int *p = 0;
*p; // UB
typeid (*p); // throws
Yes, this is ugly, even by the C++ standard of language ugliness.
OTOH, this does not work anywhere inside the argument of typeid, so adding any clutter will cancel this "feature":
int *p = 0;
typeid(1 ? *p : *p); // UB
typeid(identity(*p)); // UB
For the record: I am not claiming in this message that automatic checking by the compiler that a pointer is not null before doing a dereference is necessarily a crazy thing. I am only saying that doing this check when the dereference is the immediate argument of typeid, and not elsewhere, is totally crazy. (Maybe is was a prank inserted in some draft, and never removed.)
For the record: I am not claiming in the previous "For the record" that it makes sense for the compiler to insert automatic checks that a pointer is not null, and to to throw an exception (as in Java) when a null is dereferenced: in general, throwing an exception on a null dereference is absurd. This is a programming error so an exception will not help. An assertion failure is called for.
The only effect I can see is that 1 ? X : X gives you X as an rvalue instead of plain X which would be an lvalue. This can matter to typeid() for things like arrays (decaying to pointers) but I don't think it would matter if Derived is known to be a class. Perhaps it was copied from someplace where the rvalue-ness did matter? That would support the comment about "cargo cult programming"
Regarding the comment below I did a test and sure enough typeid(array) == typeid(1 ? array : array), so in a sense I'm wrong, but my misunderstanding could still match the misunderstanding that lead to the original code!
This behaviour is covered by [expr.typeid]/2 (N3936):
When typeid is applied to a glvalue expression whose type is a polymorphic class type, the result refers to a std::type_info object representing the type of the most derived object (that is, the dynamic type) to which the glvalue refers. If the glvalue expression is obtained by applying the unary * operator to a pointer and the pointer is a null pointer value, the typeid expression throws an exception of a type that would match a handler of type std::bad_typeid exception.
The expression 1 ? *p : *p is always an lvalue. This is because *p is an lvalue, and [expr.cond]/4 says that if the second and third operand to the ternary operator have the same type and value category, then the result of the operator has that type and value category also.
Therefore, 1 ? *m_basePtr : *m_basePtr is an lvalue with type Base. Since Base has a virtual destructor, it is a polymorphic class type.
Therefore, this code is indeed an example of "When typeid is applied to a glvalue expression whose type is a polymorphic class type" .
Now we can read the rest of the above quote. The glvalue expression was not "obtained by applying the unary * operator to a pointer" - it was obtained via the ternary operator. Therefore the standard does not require that an exception be thrown if m_basePtr is null.
The behaviour in the case that m_basePtr is null would be covered by the more general rules about dereferencing a null pointer (which are a bit murky in C++ actually but for practical purposes we'll assume that it causes undefined behaviour here).
Finally: why would someone write this? I think curiousguy's answer is the most plausible suggestion so far: with this construct, the compiler does not have to insert a null pointer test and code to generate an exception, so it is a micro-optimization.
Presumably the programmer is either happy enough that this will never be called with a null pointer, or happy to rely on a particular implementation's handling of null pointer dereference.
I suspect some compiler was, for the simple case of
typeid(*m_basePtr)
returning typeid(Base) always, regardless of the runtime type. But turning it to an expression/temporary/rvalue made the compiler give the RTTI.
Question is which compiler, when, etc. I think GCC had problems with typeid early on, but it is a vague memory.
I have this:
typedef void (*funcptr) (void);
int main(){
funcptr(); //this can compile and run with no error . WHAT DOES IT MEAN? WHY NO ERRORS?
}
The statement creates a funcptr instance by its default constructor* and discard it.
It is just similar to the code
int main () {
double();
}
(Note: * Technically it performs default-initialization as not all types have constructors. Those types will return the default value (zero-initialized), e.g. 0. See C++98 §5.2.3/2 and §8.5/5 for what actually happens.)
In C++ language, any expression of the form some_type() creates a value of type some_type. The value is value-initialized.
For example, expression int() creates a value-initialized value of type int. Value-initialization for int means zero initialization, meaning that int() evaluates to compile-time integer zero.
The same thing happens in your example. You created a value-initialized value of type funcptr. For pointer types, value-initialization means initialization with null-pointer.
(Note also, that it is absolutely incorrect to say that expressions like int(), double() or the one in your OP with non-class types use "default constructors". Non-class types have no constructors. The concept of initialization for non-class types is defined by the language specification without involving any "constructors".)
In other words, you are not really "playing with function pointer" in your code sample. You are creating a null function pointer value, but you are not doing anything else with it, which is why the code does not exhibit any problems. If you wanted to attempt a call through that function pointer, it would look as follows funcptr()() (note two pairs of ()), and this code would most certainly crash, since that's what usually happens when one attempts a call through a null function pointer value.
You are defining a datatype, funcptr, which is a function that takes no parameters and returns void. You are then creating an instance of it, but without an identifier, discarding it.