I'm working on a brigde class to work with a unmanaged c++ library. I've a problem with the following (reduced) example code:
ref class ManagedClass
{
private:
UnManagedClass* m_UnManaged;
String^ m_someString;
public:
UserAgent_Managed(String^ someString)
{
m_someString = someString;
// Compiler error
// Severity Code Description Project File Line Suppression State Error C2665 'msclr::interop::marshal_as': none of the 3 overloads could convert all the argument
// types
std::string unManagedString = msclr::interop::marshal_as<std::string>(m_someString);
// Following works
// std::string unManagedString = msclr::interop::marshal_as<std::string>(someString);
m_UnManaged = new UnManagedClass(unManagedString);
}
};
When I call std::string unManagedString = msclr::interop::marshal_as<std::string>(m_someString); with the object attribute m_someString, the compiler tells me that there is no matching marshal_as method signature. If I perform the same with the someStringparameter the compiler doesn't throw an error. What am I missing? Both m_someStringand someString have the type String^.
Thx
The marshal_as() function is not very friendly, it is missing an overload to allow this code to compile. You can hone down the problem by looking at the IntelliSense popup that shows which overloads are available. The one you are trying to use is the 4th:
std::string marshal_as<std::string, System::String^>(System::String^ const & _from_obj)
The devil is in &, an unmanaged reference. Yes, an unmanaged reference to a managed object reference, mind blown :) But perfectly legal in C++/CLI, at runtime this argument turns into a raw pointer to the object reference.
It would have compiled if the template offered a System::String^ % _from_obj overload. It doesn't. The distinction between % and & matters a lot in C++/CLI, % declares a managed reference. Called a "tracking reference" in the docs. One that the garbage collector knows about and can update when it compacts the GC heap. Otherwise semantically completely identical to an unmanaged reference.
That the GC cannot update a & reference is the hang-up here. The compiler outright forbids generating unmanaged pointers to members of a managed type, other than through pin_ptr<>. It is far too dangerous, the garbage collector can kick in any time, even while the marshal_as() function is executing. Triggered by, say, another thread that allocates objects. And move the ManagedClass object, invalidating any raw pointers to the object. Having the function continue to use the outdated pointer at runtime will make the function produce garbage and possibly corrupt the GC heap.
The someString object reference is very different, it is stored on the stack or a processor register and cannot change when a collection occurs. So no complaints from the compiler.
You already have a good workaround here, the constructor argument is good as-is. But usually you have to provide one explicitly and store the member value into a local variable. In other words, write something like this:
auto temp = this->m_someString; // Intentional temporary
auto str = marshal_as<std::string>(temp);
Related
converting my project to ARC but says it can't due to the following error 'No matching function for call to pthread_create'. Here is the code it falls in, happens specifically on the line starting with pthread create. How can I fix this? It also says Candidate function not viable: no known conversion from 'NSString *' to 'void * _Nullable' for 4th argument in the sidebar underneath the error.
I've cut off the rest of the function but can provide more detail if necessary.
void World::loadWorld(std::string name)
{
if(doneLoading==0)
{
doneLoading=1;
Resources::getResources->stopMenuTune();
if(LOW_MEM_DEVICE)
{
menu->deactivate();
Resources::getResources->unloadMenuTextures();
terrain->allocateMemory();
terrain->loadTerrain(name,TRUE);
doneLoading=2;
hud->fade_out=1;
}
else
{
terrain->allocateMemory();
pthread_t foo;
pthread_create(&foo,NULL,loadWorldThread, nsstring(name));
}
}
As your error message indicates the 4th argument to pthread_create is of type void *. Under ARC you cannot simply pass an Obj-C object reference as a void * as ARC would is not able to track the reference once it is stored in a C(++) pointer variable, and therefore cannot manage the object's memory.
For situations where an Obj-C reference must be passed into the C(++) world a bridge cast can be used to inform ARC how the memory should be managed. However in your case there a better way, just pass the C++ pointer, name, without creating an NSString. If loadWorldThread expects a std::string that is the correct thing to do anyway. If it expects an NSString * then either:
modify it to take a std::string and do any required conversion to NSString * within it; or
write a small intermediate function which takes a std::string, produces an NSString * from it, and then calls loadWorldThread. Pass this new function to pthread_create.
Doing either of the above avoids the use of a bridge cast in the pthread_create call to move the Obj-C reference into the C(++) world and out of ARC control; and another bridge cast in loadWorldThread (or intermediate function as above) to move it back into the Obj-C world and into ARC control.
Addendum
Expanding on the last paragraph, as the method there seems better suited to your situation. First, it is assumed that your code:
nsstring(name)
takes a value of type std::string and returns a value of type NSString, if it does not then look up how to do this conversion.
After the above expression you have a reference to an NSString under ARC control. You cannot simply pass such a reference as a void *, you must take it out of ARC's control first and take responsibility for its memory management (but not for long as you will see). You can bridge cast your NSString * to a CFStringRef:
CFStringRef cfName = (__bridge_retain CFStringRef)nsstring(name);
You can now pass cfName, which is a reference to a heap-allocated CFString, as a void *.
Now in loadWorldThread; which should be declared to take a void *, something like void loadWorldThread(void *arg) { ... }; you need to bridge cast your CFStringRef back to NSString * and hands responsibility for its memory management back to ARC:
NSString *nsName = (__bridge_transfer NSString *)arg;
The above is a standard pattern to pass an ARC controlled reference though an anonymous reference (void *).
(Note: the above uses CFStringRef to make it clear that you are passing around a reference to a manually managed CFString, you can cast directly to void * and back again, indeed you will notice that when casting back arg was not first cast to a CFStringRef to demonstrate this.)
HTH
I don't quite get the Objective-C selectors.
The problem is: Where are Objective-C selectors stored ?
How do Objective-C Compiler and Runtime System work, so that they convert the method names into SEL ?
Selectors are "interned" (uniquified) strings. The runtime maintains a pool of interned strings (selectors). If you want to intern a string, you call either the sel_getUid() or the sel_registerName() runtime function with a C string, and it returns an opaque handle of type SEL (the selector). If the string has already been interned before, this selector is guaranteed to be equal to the previous one. Conversely, from a selector you can get the string back using sel_getName(). In Cocoa you would use NSSelectorFromString() and NSStringFromSelector(), which operate on NSString objects, instead of using the above low-level runtime functions.
Most of the time, you will not be doing conversion between strings and selectors in the middle of your program. Instead, the selector will have already been hard-coded at compile-time. When you do a method call like [foo something: bar], it is compiled down into something like objc_msgSend(foo, #selector(something:), bar), and the selector literal like #selector(something:) will be compiled into a reference into the binary's selector table generated by the compiler, similar to with global variables. When a module is linked, its selector table is merged with the main program's selector table to guarantee the uniqueness of selectors.
The same question was bothering me too for a while. So I've looked into the runtime implementation. That's what I've found:
All the selectors are stored in a hash set. If you already have a registered selector, it will be returned by the objc runtime using c functions sel_getUid & sel_registerName, if not registered, it will be created by the same functions. Both of them have the same implementation & behavior, 'cause they are calling private function named __sel_registerName. Old runtime uses pointer to struct __objc_sel_set to store values.
struct __objc_sel_set {
uint32_t _count; /* number of slots used */
uint32_t _capacity; /* maximum number of used slots */
uint32_t _bucketsNum; /* number of slots */
SEL *_buckets; /* can be NULL if not allocated yet */
};
New runtime uses pointer to struct NXMapTable:
typedef struct _NXMapTable {
/* private data structure; may change */
const struct _NXMapTablePrototype *prototype;
unsigned count;
unsigned nbBucketsMinusOne;
void *buckets;
} NXMapTable OBJC_MAP_AVAILABILITY;
Hope this helps.
Have a look at Apples explanation:
A selector is the name used to select a method to execute for an object, or the unique identifier that replaces the name when the source code is compiled. A selector by itself doesn’t do anything. It simply identifies a method. The only thing that makes the selector method name different from a plain string is that the compiler makes sure that selectors are unique. What makes a selector useful is that (in conjunction with the runtime) it acts like a dynamic function pointer that, for a given name, automatically points to the implementation of a method appropriate for whichever class it’s used with. Suppose you had a selector for the method run, and classes Dog, Athlete, and ComputerSimulation (each of which implemented a method run). The selector could be used with an instance of each of the classes to invoke its run method—even though the implementation might be different for each.
If you have a look at #AntoniKedracki post there is a really good explanation about methods and selectors.
Just a short summary from the post:
Every objective-c method will be represented inside a struct in c. The struct looks like this:
struct objc_method {
SEL method_name
char *method_types
IMP method_imp
}
So the selector will be created by C automatically from the method name and saved inside the SEL method_name. If you want to get access to the objc_method you should include the <objc/runtime.h>, than you will be able to use the runtime methods.
For more information have a look at the link in the other post.
In code that uses blocks, you frequently see declarations such as:
typedef void(^Thunk)(void);
Thunk block1 = ^{NSLog(#"%d %p",i, &i);};
instead of
typedef void(^Thunk)(void);
Thunk *block1 = ^{NSLog(#"%d %p",i, &i);};
Blocks seem to be the only Objective-C object that is handled directly, instead of through a pointer. Why is this? Aren't they regular objects?
If you're wondering about the missing *: In your example you typedef'd the block which is hiding the syntax. You can do this with other objects as well:
typedef NSNumber *Number;
Number foo = #42;
When assigning a block to a variable that's actually assigning a pointer.
Blocks are a bit like C arrays: Block literals are structures created by the compiler. Block variables are pointers behind the scenes.
You're not handling a block “directly”. You're handling it indirectly.
The syntax void (^)(void) declares a pointer to a block. There is no syntax for type “block”; there is only syntax for type “pointer to a block”.
From the Language Specification for Blocks:
The abstract declarator,
int (^)(char, float)
describes a reference to a Block that, when invoked, takes two parameters, the first of type char and the second of type float, and returns a value of type int. The Block referenced is of opaque data that may reside in automatic (stack) memory, global memory, or heap memory.
The relevant bit is “describes a reference to a Block”.
The specification isn't entirely consistent, since (for example) it refers to a “variable with Block type” and “Block variable declarations“. But in fact a variable always holds a reference (pointer) to a block, and never holds a block directly as its value.
If you look at the block implementation, you will see that blocks are ObjC objects.
If you inspect a stack block (like in your example), you'll see something like this:
(lldb) po myBlock
<__NSStackBlock__: 0xbfffc940>
And you will notice in the public header _Block_copy() and _Block_release() take void* arguments.
The non-pointeryness is just syntactic sugar the compiler provides to shield you from the dirty bits of blocks.
Blocks are a C extension. You can use blocks in C (where the extension is supported).
Apple just happens to have implemented blocks using ObjC types.
Implementation details: Blocks are one of the few ObjC types which may be allocated on the stack using clang. Normally, this is not an option because almost every API expects that an objc_object is a heap allocation which supports reference counting.
This Question references this Question:
How to simplify callback logic with a Block?
My header has these typedefs
typedef void (^StuffDoneBlock)(NSDictionary * parsedData);
typedef void (^StuffFailedBlock)(NSError * error);
And in init
stuffDoneCallback = Block_copy(done);
StuffFailedCallback = Block_copy(error);
In this paper its says that Block_copy is unnecessary. But then it needs a bridged cast.
The compiler message is at follows:
error: cast of block pointer type 'StuffDoneBlock' (aka 'void (^)(NSDictionary *__strong)') to C pointer type 'const void *' requires a bridged cast [4]
stuffDoneCallback = _bridge(Block_copy(done));
^~~~~~~~~~~~~~~~
/Developer-4.2/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk/usr/include/Block.h:60:61: note: instantiated from:
#define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))
^~~~~~~~~~~~~~~~~~~~~~~~~~~
First off, why are you even using Block_copy()? Unless you're writing raw C, you should be calling -copy on the block instead, as in [done copy]. Secondly, ARC will copy blocks for you that need to live past their initialization scope[1], so you don't need to even call -copy anymore. The only "exception" is that block-typed properties still need to have the copy attribute.
[1]: Clarification appears to be needed here. ARC only implicitly copies blocks when the compiler sees that it needs to live past its initialization scope. This basically means when it's assigned to a variable that escapes the current scope (stack variable declared in a parent scope, instance variable, static, etc.). However, if it's passed as an argument to a method/function, the compiler does not do any automatic copying. Typically this isn't a problem because block-aware methods/functions that need to hold onto the block past the stack frame (dispatch_async(), completion blocks, etc.) will copy them for you. However, APIs that are not block-aware (such as NSArray) will not implicitly copy the block, since they expect that a simple -retain will do the trick. If you're passing your block to a non-block-aware API and the block needs to live past the current scope, you must use an explicit -copy.
The Compiler claims an error saying: "initializer element is not constant", when I try to initialize a static variable inside a method with a call to a static method (with + in its definition).
Anyway I can tell him that this method always returns the same value. I know this is not the same as static method, but there seems to be no constant methods in Objective-C (other than macros which won't work here because I am calling UI_USER_INTERFACE_IDIOM() from inside the method).
There's actually another solution in addition to Yuji's. You can create a function and prefix it with a GCC attribute (also works in Clang and LLVM) that will cause it to be executed before main() is. I've used this approach several times, and it looks something like this:
static NSString *foo;
__attribute__((constructor)) initializeFoo() {
foo = ...;
}
When you actually use foo, it will already be initialized. This mean you don't have to check whether it's nil each time. (This is certainly a minor performance benefit, though multiplied by the number of times you use it, but it can also simplify one or more other regions of code. For example, if you reference the static variable in N different places, you might have to check for nil in all N or risk a crash. Often, people call a function or use a #define to handle initialization, and if that code is only actually used once, it can be a penalty worth removing.
You cannot do that in Objective-C.
There are two solutions:
Switch to Objective-C++. Change the file extension from .m to .mm.
Initialize it with nil, and check it when you first use it, as in:
static NSString*foo=nil;
if(!foo){
foo=[ ... ] ;
}