It's worth noting that even in this case it needs to be used with care.
If one assigns one CryStringT object to another (ref count is 2) and uses one of them in another thread, passing it along in some data structure or something, it can wreak havoc. It's not unreasonable to be responsible for protecting your own shared data, but the COW code is not thread safe either. I believe in the standard library 2 separate string objects are not supposed to have any hidden surprises like that (though it has been a problem in the past).
Crunch may be worth looking at. It has a fairly high compression rate, and instead of decompressing to raw image data, it was designed to directly transcode (sort of cross-compressing) directly to DXTn for sending to your gpu. Also, as stated on the site, it can output directly to DDS image format, which it specifically optimizes to be highly compressible using standard compression (Zlib, LZMA, etc).
I've never used it but only because I don't find this issue much in my work. Otherwise it is probably the first thing I'd check out. I did some what follow its development.
Also I'm not sure what it can do as far as lossless compression goes if that was your goal.
 If you just need something simple I'd use PNG with libpng. It's a fair trade-off of simple-to-implement and general image compression.
More importantly than learning about pointers themselves, IMHO, is that learning them is a great first step to learning about memory. This will be invaluable later on as you gain more experience, especially when it comes to optimization (whether for speed or other types of targets).