I have got a class that has overloaded unary operator&. The objects of that type were created using new, so address of variable was accessible but now I need to use static object. Is it possible to get its address?
In C++11 or later, std::addressof(object), declared by the <memory> header.
Historically, it was more grotesque, especially if you wanted to deal with const and volatile qualifiers correctly. One possibility used by Boost's implementation of addressof is
reinterpret_cast<T*>(
&const_cast<char&>(
reinterpret_cast<const volatile char &>(object)))
first adding qualifers while converting to char& so that reinterpret_cast would work however object were qualified; then removing them so that the final conversion would work; then finally taking the address and converting that to the correct type. As long as T has the same qualifiers as object (which it will as a template parameter deduced from object), the resulting pointer will be correctly qualified.
Since C++11, you may use the function std::addressof
Related
I asked a related, tedious question before and now I discover something new.
#include <iostream>
#include <string>
using namespace std;
void hello (const string &s1) {
cout << "rocky" << endl;
}
void hello(string &s1) {
cout << "banana" << endl;
}
int main()
{
string s = "abc";
hello(const_cast<const string&>(s)); //how to explain this const_cast?
}
hello(const_cast<const string&>(s)); this works and match the const reference parameter function. So how's the conversion this time? Isn't it string to const string&?
Certainly I know that const reference can be initialized with non-const objects... But somehow I never take that as a conversion. I see it as an assignment. And I consider the type of reference and the type of referent as two very different stuff.
So, primary meaning for the cast is to pick necessary one from the list of overloaded hello() functions. Without the cast, we pick non-const version, otherwise it's const one.
Secondly, why the cast of the string reference, not just string type? This is due limitations of the const_cast itself. Let's try to compile that:
hello(const_cast<const string>(s)); // we removed the "&"
compiler message:
error: invalid use of const_cast with type ‘const string {aka const std::__cxx11::basic_string<char>}’,
which is not a pointer, reference, nor a pointer-to-data-member type
So, const_cast is not intended to create new instance, instead it works with indirection to given instance and just changes associated CV qualification (as it's free lunch in terms of code generation). So, we have to deal with a pointer or reference to conform that condition.
P.S. As far as I know, C++17 allows creation of temporary copies for the casting (aka Temporary materialization) so our non-ref attempt could have practical meaning. Same time, it's quite new concept and not so wide-spread.
Expressions, objects, variables - I know C++ can be a bit confusing to newcomers, especially when it comes to the subtle details.
So s here is a variable in main. While main runs (and that's the whole program, since it's main), there is an object that corresponds to the variable. And in main, the expression s refers to to that object. But there are many more expressions that refer to the same object. (s) is another expression that refers to the same object. So is *&s. Or *(&s).
s+"" is another expression that has the same value. But it's not the same object. Cf. integers i+0 or i*1.
References can be used to define variables which introduce new names for objects, names that can then be used in expressions. There are many places where it's convenient to be able to explicitly name something. It's just a new name, not a new object.
const_cast is another use for references. This however doesn't introduce a new name; it just forms a new expression with a const added to the type.
Now to your hello. This is an overloaded function. Overload resolution is done on the type of the expression used as an argument. So in hello(s1), s1 is the simple expression used for overload resolution, and its type is std::string. In hello(const_cast<std::string const&>(s1)), the expression is const_cast<std::string const&>(s1), and its type is obviously std::string const&.
Both expressions refer to the same object; they only differ in type. But that type difference is exactly what overload resolution needs.
You can only convert from const reference to lvalue reference explicitly by using const_cast as such conversion is not safe and must be explicit. On another side you can convert from lvalue or lvalue reference to const reference implicitly or explicitly, as such conversion is safe. So usually nobody cast to const reference explicitly as it is unnecessary verbose and does not make sense. In your case it is converted explicitly to select certain overloaded function, because compiler would not convert it implicitly, as it can find overload with lvalue reference, but your example is rather artificial, as it is difficult to imagine why somebody would have such overload.
I'm coding c++11.
In a class A, I have a member variable "member" which is defined as
vector<OtherClass> member; // A's member variable
I would like to serialize A ( so I want to all the data type in OtherClass contained in the vector ) into file in binary format so I defined a function write as follows.
void A::write(ostream& os){ // A's function for outputting A
os.write(reinterpret_cast<const char*>( &(member.size()) ), sizeof(member.size()));
}
But compiler said lvalue required as unary '&' operand.
How can I fix it without creating a temporary object such as long size=member.size() in the write function?
The problem is &(member.size()) - you're not assigning size()'s return value and trying to take the address of it (it may not even have an address).
But no idea why you're calling size here anyway you need the start address of the actual data: member.data() (or if you dont have C++11 &member[0])
"How can I fix it without creating a temporary object"
You can't. You want to use &, which takes the address of an object. No object, no address. It's really that simple.
Note that your long size = member.size() idea doesn't create a temporary variable. That's an ordinary variable.
I have a template member function with this signature:
template<typename T> void sync(void (*work)(T*), T context);
It can be called with a pointer to a function that accepts an argument of type T*. context is passed to that function. The implementation is this:
template<typename T> void queue::sync(void (*work)(T*), T context) {
dispatch_sync_f(_c_queue, static_cast<void*>(&context),
reinterpret_cast<dispatch_function_t>(work));
}
It uses reinterpret_cast<> and it works. The problem is that the standard doesn't define it very well and it is very dangerous. How can I get rid of this? I tried static_cast but that gave me a compiler error:
static_cast from void (*)(std::__1::basic_string<char> *) to dispatch_function_t (aka void (*)(void *)) is not allowed.
dispatch_function_t is a C type and is the same as void (*)(void*).
I'm not sure I was clear enough. What dispatch_sync_f does is it calls a given callback function and passes the given context parameter to that callback function. (It does that on another thread, although that is out of the scope of this question.)
The reason this is not supported by static_cast is because it is
potentially unsafe. While a std::string* will convert implicitely to
a void*, the two are not the same thing. The correct solution is to
provide a simple wrapper class to your function, which takes a void*,
and static_casts it back to the desired type, and pass the address of
this wrapper function to your function. (In practice, on modern
machines, you'll get away with the reinterpret_cast, since all
pointers to data have the same size and format. Whether you want to cut
corners like this is up to you—but there are cases where it's
justified. I'm just not convinced that this is one of them, given the
simple work-around.)
EDIT: One additional point: you say that dispatch_function_t is a C type. If this is the case, the actual type if probably extern "C" void (*)(void*), and you can only initialize it with functions that have "C" linkage. (Again, you're likely to get away with it, but I've used compilers where the calling conventions were different for "C" and "C++".)
I guess, you are not only casting work to dispatch_function_t, but calling it through dispatch_function_t pointer, aren't you? Such cast itself is valid according to standard, but all you can do with a casted pointer is cast it back to original type. Still your approach should work with most compilers and platforms. If you'd like to implement it so it's more standard conforming you can make a wrapper for your context and work function like this:
template <typename T>
struct meta_context_t
{
T *context;
void (*work)(T*);
};
template <typename T>
void thunk(void *context)
{
meta_context_t<T> *meta_context = static_cast<meta_context_t<T> *>(context);
meta_context->work(meta_context->context);
}
template<typename T> void queue::sync(void (*work)(T*), T context) {
meta_context_t<T> meta_context =
{
&context,
work
};
dispatch_sync_f(_c_queue, static_cast<void*>(&meta_context),
thunk<T>);
}
I can't believe this works or you have a rather narrow definition of "this works" (e.g. you found one particular setup where it seems to do what you think it should do). I'm not clear what dispatch_sync_f() does but I think it is suspicious that it gets a pointer to the local variable context as parameter. Assuming this variable outlives the use of this pointer, there is still a subtle problem which won't get you on most platforms but does get you on some:
C and C++ calling conventions can be different. That is, you cannot cast a pointer to a C++ function to a pointer to a C function and hope for this to be callable. The fix to this problem - and your original question - is, of course, an extra level of indirection: don't dispatch to the function you get as argument but rather dispatch to a C function (i.e. a C++ function declared as extern "C") which takes its own context holding both the original context and the original function and calls the original function. The only [explicit] cast needed is the static_cast<>() restoring a pointer to your internal context from the void*.
Since you seem to implement a template you might need to use another indirection to get rid of this type: I don't thing function templates can be declared extern "C". So you would need to restore the original type somehow e.g. using a base class and a virtual function or something like std::function<void()> holding a readily callable function object doing this conversion (a pointer to this object would be your context).
I believe the cast to/from these two function pointer types is fine:
void(*)(void*)
void(*)(T*)
The problem is that you can't actually use the pointer that you have so cast. It's legal only to cast back to the original type (and those casts are reinterpret_cast, because these are unrelated types). From your code, I can't see how your actual callback function is defined. Why can't you accept a dispatch_function_t as your parameter for queue::sync, rather than casting it?
reinterpret_cast is guaranteed to work when converting from a type T * to void * and back. It is, however, not acceptable to cast from or to a pointer to a base or derived class of T.
The type of work needs to be dispatch_function_t in this case, and the first order of business in that function needs to be the cast from void * to T *. Implicitly casting the argument by using a different argument type and casting the function type is not allowed.
Rationale: the standard allows different pointer representations for different types, as long as all pointer types can be converted to void * and back, so void * is the "most precise" pointer type. A conforming implementation is allowed to clear the bottom-order bits of an uint32_t * if sizeof(uint32_t) > sizeof(char) (i.e. sizeof(uint32_t) > 1) or even shift the pointer value if the machine instructions can utilize these pointers more effectively; on a machine with tagged or shifted pointer values the reinterpret_cast is not necessarily a no-op and needs to be written explicitly.
I have a following template defined so that I can perform an explicit, but safe cast:
/// cast using implicit conversions only
template <class To,class From>
inline To safe_cast( const From &from ) {return from;}
Frequently (e.g. when passing arguments into sprintf and similar functions) I would like to use this template to perform a conversion from a string class to a c-style string. However, it shows this is not possible when temporary is passed, because the temporary will not live long enough.
Consider following example:
class Object
{
public:
MyStringClass GetDebugName() const;
};
Object obj;
printf("%s",safe_cast<const char *>(obj.GetDebugName()));
The temporary from obj.GetDebugName() lives only during the safe_cast and the pointer is invalid (points to the data of the string temporary which has already been destroyed) when inside of the printf.
As a workaround I a currently using direct cast without a template call: const char *c = (const char *)(obj.GetDebugName(), but this has a drawback of reduced type safety, as the cast is unnecessarily strong (e.g. it would silently succeed even if obj.GetDebugName() would be returning int instead of a string value). static_cast might be slightly better, but even that is too strong, I would like to get an error on any situation where cast is not sure to be safe.
1) If I am not mistaken, the standard says the temporary life time is a statement (unless extended by being bound to a const reference, in which case it is the life time of the reference). When looking at the printf example above, I am not quite sure what a "statement" is, and if the behaviour I have seen is conformant or not. If the statement is the whole printf, the lifetime of the const From &from is shorter - what lifetime should I expect from the temporary? Can someone clarify?
2) Is there some other way to make a conversion which would be safe, but the result would live long enough to be useful?
Edit:
Please, consider this more a kind of general question, I am seeking for a mechanism how can a conversion like this to be done with regard to the temporary lifetime, I am not that much interested in a special case of any particular string class.
To clarify why I do not want to use .c_str or a similar member function: I would like the conversion code to be type agnostic, I do not want the code to rely on the fact I know this particular string type has c_str implemented, I want it to work even if a different string class would be returned by ObjectDebugName, or even if ObjectDebugName would be already returning const char * (which excludes the possibility of calling .operator const char *().
I can perform an explicit, but safe cast
I would call it an implicit cast done explicitly, or just and explicit implicit cast.
1) If I am not mistaken, the standard says the temporary life time is a statement (unless extended by being bound to a const reference, in which case it is the life time of the reference). When looking at the printf example above, I am not quite sure what a "statement" is, and if the behaviour I have seen is conformant or not. If the statement is the whole printf, the lifetime of the const From &from is shorter - what lifetime should I expect from the temporary? Can someone clarify?
You are correct, the temporary is destroyed after printf've returned.
The code you provided should work. If it doesn't, it means that you misprovided some important information.
I don't know why you are using your own string class here. Does the class have a member function to get the const char * out of it?
std::string GetDebugName();
printf( "%s", GetDebugName().c_str() );
would be safe as the temporary would remain valid during that statement, for example.
You can call the conversion function directly:
printf("%s", obj.GetDebugName().operator const char*());
I want to compile the following line of code from http://code.google.com/p/enhsim:
enh::eout << enh::setw(26);
gcc gives the following error:
error: no match for 'operator<<' in 'enh::eout << enh::setw(26)'
But the EnhSimOutput class (of which enh::eout is an instance) does declare:
EnhSimOutput& operator<< (setw& p);
This problem goes away if I implement a version of the operation that accepts the object by value:
EnhSimOutput& operator<< (setw p);
or if I create the enh::setw object as a local, i.e.:
enh::setw wValue(26);
enh::eout << wValue;
My question is this: why does gcc not select the "by-reference" version of the operator to begin with?
The developers who wrote this code clearly made it compile, yet default gcc refuses to do it. Why is there a difference between an object declared separately as a local variable and a local created inline?
The value enh::setw(26); is an rvalue . Actually, temporaries like that are rvalues. Rvalues have special properties. One of them is that their address can't be taken (&enh::setw(26); is illegal), and they can't generally bind to references to non-const (some temporaries can bind to references to non-const, but these undergo special rules: Calling member functions on temporary objects and catching exception objects by reference to non-const. In the latter case, the temporary even is an lvalue).
There are two kind of expressions: lvalues that denote objects (that in turn may store an value) or functions, and rvalues which are meant to represent values read out of an object or represented by temporaries, numeral literals and enumerator constants. In C++03, to be able to pass such values to a function that accepts its value by-reference, there is a rule that they can be accepted by reference-to-const: setw const& p would accept it. That is, you would have to declare your operator like this:
EnhSimOutput& operator<< (setw const& p);
That's a bit unfortunate, because you can't disambiguate constant lvalues (objects you created on the stack using const enh::setw e(26); for example) and non-const or const rvalues (like enh::setw(26); which is a non-const temporary). Also, if you go by that, the parameter can't have called non-const member functions on it, because it's a reference-to-const. For that reason, C++1x, the next C++ version, introduce a new kind of reference, so-called rvalue-references which fixes that.
The Microsoft Visual C++ compiler binds rvalues to references to non-const, but gives out a warning when doing that (you have to use at least warning level 4 for it to show up). That's unfortunate, because problems rise up when porting to other compilers that are more strict in Standard compliance.
My guess is that EnhSimOutput& operator<< (setw& p); passes by non-const reference, but the value 26 is "const" in the sense that it cannot be modified. Try setting it to EnhSimOutput& operator<< (const setw& p);
or try
int nNumber = 26;
enh::eout << enh::setw(nNumber);