An immutable class is intrinsically thread-safe.
Roughly speaking, concurrency issues occur when a write can run concurrently with any other read or write of the same data.
Think of shared and exclusive locks. Reads are performed by acquiring a shared lock, and writes require acquiring an exclusive lock. Any number of threads can concurrently own a shared lock. Only one thread can own an exclusive lock at the same time, and no shared lock can be held while an exclusive lock is held. This means you can perform reads concurrently, but not writes nor reads and a write. If your data can never be modified, then there will be no concurrency issues (no need for exclusive locks and therefore, shared locks make no sense).
This is one of the advantages of functional languages: data is never modified, making functions inherently thread safe and allowing for aggressive compiler optimizations.
Now, there is another question about thread safety that is usually forgotten: the memory model, specially in modern NUMA architectures.
If you know about volatile variables, the point is the compiler is free to optimise data access as long as the progran remains correct.... in single-threaded processing.
If the compiler is not aware that another thread may read or write a variable concurrently, it may keep the value in a register and never check for changes in main memory. This can happen also with cached values in different levels of cache. It may even optimize out a conditional branch if it knows the result of the condition in compile time and doesn't know the values involved may change nondeterministically.
Declaring a variable volatile indicates its value may change and forces to flush to main memory every time and read from main menory too.
But why would this be needed, if the value never changes? Well, the value changes during construction, which cannot be assumed to be instantaneous or atomic. If the compiler doesn't know it's multithreaded, it may even never flush any data to main memory. If you make a reference to this object available to another thread, it will read it from main memory, where it has never been initialised. Or it can even see the initialization taking place (this could happen when initialising a big String in old versions of java).
I believe modern C++ standards define a memory model, but I haven't digged into it yet. If the memory model is unspecified or is not strong enough, you may always need to execute primitives, such as acquiring or releasing a lock, which establish a "happens before" relationship. In any case, you definitely need to tell the compiler that data is either volatile or immutable, so that it can provide the guarranties of the memory model in use.
In this case, I would declare the variable and the getter method with const modifiers. I'm quite sure it will work just fine, but I recommend studying the memory model of the standard you are using and switch to a more modern standard if needed.