coding challenges · advanced

Generic Key-Value Store — any vs variant

Microsoft generic key-value store (string key, any-type value). Store heterogeneous types with std::any (unbounded types, type-erased, RTTI, may heap-allocate) or std::variant<...> (a known closed set — no RTTI, inline, visitable). The crux is safe retrieval: use the pointer form any_cast<T>(&value) (or std::get_if<T> for variant), which returns nullptr on a type mismatch, and wrap the result in std::optional<T> so a missing key or wrong type yields an empty optional instead of throwing bad_any_cast. For concurrency use a std::shared_mutex: get takes a shared_lock (many readers), put/erase take a unique_lock (one writer); mark it mutable and return values by COPY so a concurrent erase can't dangle a reference. O(1) average put/get. Scale follow-ups: shard the map with striped locks, add TTL/LRU eviction, and serialize via std::visit. Prefer variant when the value types are known, any when callers store arbitrary types.

🔑 Key line

Generic KV store: string→std::any (any type, runtime-checked) or string→std::variant<...> (closed set, compile-time, visitable). Safe get<T> uses the POINTER form any_cast<T>(&v)/get_if<T> → optional<T> (no throw on wrong type). Thread-safety: shared_mutex (shared_lock readers, unique_lock writers); return by value to avoid dangling. O(1) avg; scale via sharded locks + TTL/LRU eviction.

The code

// Generic in-memory KV store: string key, value of ANY type.
// Option A — std::any (type-erased, runtime-checked).
class Store {
std::unordered_map<std::string, std::any> m_;
mutable std::shared_mutex mtx_;
public:
template<class T>
void put(const std::string& k, T v) {
std::unique_lock lk(mtx_); // writer: exclusive
m_[k] = std::move(v);
}
template<class T>
std::optional<T> get(const std::string& k) const {
std::shared_lock lk(mtx_); // readers: shared
auto it = m_.find(k);
if (it == m_.end()) return std::nullopt;
if (auto* p = std::any_cast<T>(&it->second)) return *p; // type match?
return std::nullopt; // wrong T -> empty, no throw
}
bool erase(const std::string& k) {
std::unique_lock lk(mtx_);
return m_.erase(k) > 0;
}
};
// Option B — std::variant<int,double,std::string,...> when the value set
// is a KNOWN, closed list of types (visitable, no RTTI, smaller).

What this lesson walks through

  1. 01One map, values of any type
  2. 02Safe get — pointer-cast into optional<T>
  3. 03Thread-safe with a readers/writer lock
  4. 04variant when the type set is closed
  5. 05What the question really tests

Key is a string, value can be any type. Two clean ways to hold heterogeneous types in one map: std::any (unbounded set, checked at runtime) or std::variant<…> (a known closed set, checked at compile time and visitable).

See it animated — step by step, at your own pace

Unlock the full interactive walkthrough of Generic Key-Value Store — any vs variant and 100+ animated C++ interview lessons.

← Previous
State Machine with std::variant
Next →
Thread-Safe Circular Buffer