Passing the address of dereferenced smart pointers to functions that expect raw pointers

Yes, that is valid practice. The std smart pointers have a get() member function exactly for that purpose.

In general, when you manage an object through smart pointers, you should only pass the whole smart-pointer-object as is to other functions when these functions imply ownership semantics: if a function will copy a std::shared_ptr, it should accept it by value. Similar for std::unique_ptr. More often than that, a function doesn't have anything to do with ownership, it just wants to act on data and/or behavior passed into it. Then, your first choice should be to take a (const-qualified) reference, because it doesn't have the additional nullptr-state of pointers. Otherwise, a pointer is just fine.

Long story short: if you deal with an API that accepts raw pointers and doesn't do any ownership-related actions on it (delete it, copy the pointee), then it's fine to pass .get() to it.

As long as the function doesn't expect to take ownership of the data, definitely.

In fact, that is also how you should design your own functions: use a smart pointer in an interface if, and only if, it should participate in the ownership of the pointee.

Is it valid practice to use a smart pointer which owns some data, and then pass the address of the derefenced smart pointer to a function that expects a raw pointer?

Yes, that is potentially a valid practice... as long as that function doesn't take ownership of that raw pointer. However, it is important to take note how long the passed pointer will be used. The lifetime of the smart pointer must match or exceed the use of that pointer.

In case the function does take ownership, then it may instead be a valid practice to pass an address released from the smart pointer, but only if the deleter matches what the framework would do with the pointer.