---
source_url: https://www.pubnub.com/docs/sdks/windows-cpp
title: Windows C++ API & SDK Docs 7.2.3
updated_at: 2026-06-05T11:13:53.335Z
sdk_name: PubNub Windows C++ SDK
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Windows C++ API & SDK Docs 7.2.3

PubNub Windows C++ SDK

## Get code: source

:::note SDK version
Always use the latest SDK version to have access to the newest features and avoid security vulnerabilities, bugs, and performance issues.
:::

[https://github.com/pubnub/c-core](https://github.com/pubnub/c-core)

[View Supported Platforms](https://www.pubnub.com/docs/sdks/windows-cpp/platform-support)

## Hello World

### Makefiles

We recommend you use the Makefiles as a starting point in your own projects (whether they are based on Make or some other build tool / system or IDE).

**The Makefile to build for Windows C++** is available at [windows.mk](https://github.com/pubnub/c-core/blob/master/cpp/windows.mk) Please take a look at [/cpp/README.md](https://github.com/pubnub/c-core/blob/master/cpp/README.md) for general info about the repo layout & contents.

**The Makefile for Windows C++ with SSL/TLS** (via OpenSSL) is available at [windows_openssl.mk](https://github.com/pubnub/c-core/blob/master/cpp/windows_openssl.mk) in the repo. See [README.md](https://github.com/pubnub/c-core/blob/master/openssl/README.md) for info on how to build w/OpenSSL on Windows C++ and other OpenSSL related data.

### Including the header

To include the PubNub Windows C++ headers into your app, you must include `pubnub.hpp`:

```cpp
#include "pubnub.hpp"
```

Once the header has been included, its easy to make calls to the PubNub service via the Windows C++ API. The PubNub Windows C++ API is very flexible, supporting many different calling patterns. As such, before we dive in to actual coding samples, its important to go over the different types of calling patterns provided by the PubNub Windows C++ client's futures support.

### C++ calling patterns: futures

:::note pubnub::futres naming
The `pubnub::futres` class name is a portmanteau, blending C++ `future` with `enum pubnub_res`. It was purposely not named `pubnub::future` to avoid namespacing conflicts.
:::

Both POSIX and Windows C++ SDKs use the `pubnub::futres` class, based on the `std::future` class (introduced in C++ 11) which provides a way to track the outcome of an operation asynchronously. Every operation that the SDK initiates with PubNub returns a `futures` object. This object allows to track the progress and completion of the operation via the status identifiers.

#### Using futures synchronously

There are several ways to use futures synchronously:

* Single `await()` or `get()`
* Separated `start_await()` and `end_await()`
* Your own `last_result()` loop

##### Single await() or get()

The `pubnub::futres::await()` method, similar to the `pubnub_await()` function from the C `sync` interface, is used to await the outcome of a transaction/operation. Since its function is the same as `std::future<>::get()`, we provide a `synonym`, and you can call `pubnub::futres::get()` with the same effect.

```cpp
pubnub::context pb("demo", "demo");
pubnub::futres f = pb.publish("hello_world", "\"Here I am!\"");
if (PNR_OK == f.await()) {
    std::cout << "Published OK" << std::endl;
}
pubnub::futres f = pb.publish("hello_world", "\"Stuck in the middle\"");
if (PNR_OK == f.get()) {
    std::cout << "Published OK (again)" << std::endl;
}
```

##### Separated start_await() and end_await()

You don't have to await `at once`. You can start the await, and finish later. This is useful if you are working with more than one context, so you start an operation on one context, then start the await on that context, proceed to start an operation on another context and then end the started await.

```cpp
pubnub::context pb("demo", "demo");
pubnub::context pbsub("demo", "demo");
pbsub.subscribe("hello_world").await();  // connect
pubnub::futres fsub = pbsub.subscribe("hello_world");
fsub.start_await();
pubnub::futres f = pb.publish("hello_world", "\"with you!\"");
if (PNR_OK == f.await()) {
    std::cout << "Published OK" << std::endl;
}
if (PNR_OK == fsub.end_await()) {
    std::cout << "Received messages:" << std::endl;
    for (auto &&msg : pbsub.get_all()) {
        std::cout << msg << std::endl;
    }
}
```

##### Your own last_result() loop

You don't have to use the `await()` functions. You can call `last_result()` in a loop and perform other operations. If you aren't doing other operations, this pattern won't be that useful for you -- in that case, just call `await()`.

```cpp
pubnub::context pb("demo", "demo");
pubnub::futres f = pb.publish("hello_world", "\"Waiting for Godot\"");
for (;;) {
    pubnub_res result = f.last_result();
    if (result() == PNR_STARTED) {
        // Do something while we wait
        play_some_tetris();
    }
    else if (PNR_OK == f.get()) {
        std::cout << "Published OK" << std::endl;
    }
}
```

#### Using futures asynchronously

All asynchronous logic is built upon `pubnub::futres::then()` (similar to what is available in some `future` libraries, and proposed for addition to C++17). There are several ways to use futures asynchronously:

* Using futures with a callback
* Using futures with a lambda
* Using futures with a function object

##### Using futures with a callback

By providing a free function or a static class method, you'll be using the C++ client similarly to that of the C `callback` interface.

:::note Required UUID
Always set the `UUID` to uniquely identify the user or device that connects to PubNub. This `UUID` should be persisted, and should remain unchanged for the lifetime of the user or the device. If you don't set the `UUID`, you won't be able to connect to PubNub.
:::

```cpp
static void on_publish(pubnub::context &pb, pubnub_res result)
{
    if (PNR_OK == result) {
          std::cout << "Published OK" << std::endl;
      }
}

int main(int argc, char *argv[])
{
    pubnub::context pb("demo", "demo");
    pubnub::futres f = pb.publish("hello_world", "\"Don't call us\"");
    f.then(on_publish);
    return 0;
}
```

##### Using futures with a lambda

Instead of a function, you can also pass a lambda to `pubnub::futres::then`:

```cpp
pubnub::context pb("demo", "demo");
pubnub::futres f = pb.publish("hello_world", "\"Lambda\"");
f.then([=](https://www.pubnub.com/docs/pubnub::context &pb, pubnub_res result) {
    if (PNR_OK == result) {
        std::cout << "Published OK" << std::endl;
    }
    pubnub::futres f2 = pb.publish("hello_world", "\"the ultimate\"");
    f2.then([=](https://www.pubnub.com/docs/pubnub::context &pb, pubnub_res result) {
        if (PNR_OK == result) {
            std::cout << "Published OK (nested)" << std::endl;
        }
    });
});
```

##### Using futures with a function object

You can pass a callable object to `pubnub::futres::then()` - that is, an object of a class with an overloaded function call operator:

:::note Required UUID
Always set the `UUID` to uniquely identify the user or device that connects to PubNub. This `UUID` should be persisted, and should remain unchanged for the lifetime of the user or the device. If you don't set the `UUID`, you won't be able to connect to PubNub.
:::

```cpp
class bean_counter {
    int beans;
    public:
        bean_counter() : beans(0) {}
        void operator()(pubnub::context &pb, pubnub_res result) {
            if (PNR_OK == result) {
                ++beans;
            }
                  std::cout << "Published " << beans << " beans" << std::endl;
        }
};

int main(int argc, char *argv[])
{
    pubnub::context pb("demo", "demo");
    bean_counter hermes_conrad;
    for (int i = 0; i < 1000; ++i) {
        pubnub::futres f = pb.publish("hello_world", "\"Stamp\"");
        f.then(hermes_conrad);
    }
    return 0;
}
```

Since `std::function<>` is a generic function object, if you have one, just pass it to `pubnub::futres::then:`

```cpp
void planet_express(std::function<void(pubnub::context&,pubnub_res)> parcel)
{
    pubnub::context pb("demo", "demo");
    pubnub::futres f = pb.publish("hello_world", "\"Deliver\"");
    f.then(parcel);
}
```

### Memory allocation

This client uses dynamic memory allocation for the PubNub contexts, but the usage is the same as for any other Pubnub C client - always use `pubnub_alloc()` to create a context (and check its return value) and always use `pubnub_free()` to dispose of a context.

:::note Required UUID
Always set the `UUID` to uniquely identify the user or device that connects to PubNub. This `UUID` should be persisted, and should remain unchanged for the lifetime of the user or the device. If you don't set the `UUID`, you won't be able to connect to PubNub.
:::

```cpp
#include "pubnub_alloc.h"
#include <stdio.h>
int main()
{
    pubnub_t *ctx = pubnub_alloc();
    if (NULL == ctx) {
        puts("Couldn't allocate a Pubnub context");
        return -1;
    }
    /* Do something with ctx...
        and then: */
    pubnub_free(ctx);
    return 0
}
```

### Timers

We only provide one timer - the `(total) transaction` timer. In general, it is started when a transaction is started and stopped when a transaction is finished. If it expires, the transaction will be cancelled. Keep in mind that this canceling is local, so, for example, if you already published a message, but, for some reason, the HTTP response didn't arrive in time, this canceling will not `revoke` the publish - it will just stop the wait for response.

If the transaction timer expires, the outcome of the transaction will be `timeout` - different than when you cancel a transaction yourself.

The actual duration of the timer is at least as long as you set it. It could be significantly higher, depending on various platform issues. But, in general, it will be close to what you set.

You should set the timer after initializing the context and before starting a transaction. The duration you set will be used for all subsequent transactions, regardless of their type (i.e. for publish and subscribe and all other).

### Thread safety

C-core supports thread-safe operation, though, for performance, you may think about not using it. To use thread-safety support, define the preprocessor symbol `PUBNUB_THREADSAFE` (just define it, the value does not matter).

#### Thread-safe usage

Thread safety is internal. Just because you can access the PubNub context through the PubNub C-core SDK API from different threads safely, doesn't mean you're `off the hook` for your own data that is related to a context. For example, if you're using the callback interface and signalling an event from it to other (`worker`) thread(s), you have to synchronise that data transfer yourself.

If you compiled thread-safety support in, you are free to access the same context from different threads, pretty much in any way you wish. However, there are some advised guidelines you should follow:

* If you're using the sync blocking interface, threads that come to wait on the context may wait a long time, so try to avoid it (also, re-think your whole need for a thread-safe C-core)
* If you're using the sync non-blocking interface by calling `pubnub_await`, things are pretty much the same as for sync blocking interface
* If you're using the sync non-blocking interface and avoid `pubnub_await`, waiting threads will not block so long, but, pretty much the only useful thing you can do is cancel a transaction from another thread.
* Using the sync interface, it's perfectly fine to call `pubnub_await` or `pubnub_last_result` in different threads, but, you probably shouldn't do that, as it will make debugging harder.
* If you're using the callback interface, it's perfectly fine to call Functions from your callback, but, you should avoid doing that, except for some helper functions. Following this guideline will make your debugging, thus life, a lot easier

#### Thread-unsafe usage

If you compile without thread-safety support, obviously, you will have an SDK which is not thread safe - that is, it is not safe to use a single context from more than one thread at the same time. So, if you're using such SDK configuration in a multithreaded code, which, on WINDOWS, you likely are, then:

1. If at all possible, use a single context from only one thread - the one that created it.
2. If this is not possible, provide some synchronization yourself, for example, using pthread condition variables, or just mutexes, or some higher abstraction, like message queues.
3. As a special case, if you're using the callback interface, you can start a transaction in one thread and then don't touch the context from that thread any more - use it only in the callback. This is safe.

:::note Context usage
Keep in mind that it is perfectly safe to use different contexts from different threads at the same time. To each (thread) its own (context).
:::

Keep in mind that it is perfectly safe to use different contexts from different threads at the same time. To each (thread) its own (context).

### Transaction and operation

The Windows C++ SDK operates as a set of transactions. A transaction is initiated by the client SDK and is defined as a single message exchange between the SDK and PubNub service. Every interaction that the client SDK initiates with PubNub is sequenced as a series of transactions which ultimately results in a PubNub service-specific operation.

### Status and Events

The SDK provides a set of status and event identifiers which can help developers interact with the library. The status identifier codes are returned as part of the SDK's API invocation. These are used by the developer to check for status of transactions or for detecting normal / abnormal conditions in an API call. Some of the commonly used status codes are as follows.

* `PNR_OK` : Success, the transaction finished successfully
* `PNR_STARTED` : The previously initiated transaction has started.
* `PNR_IN_PROGRESS` : Indicates that the previous transaction with PubNub service is still in progress.

Refer to the API docs for a complete list of status identifiers supported by the library.

`Events` refer to the PubNub REST operations which are initiated by the client SDK. The most common example of events are subscribe and publish. A client subscribing for a channel is a subscribe event and a client publishing a message on a channel is a publish event.

Some of the common event identifiers are as follows:

* `PBTT_SUBSCRIBE` : Subscriber operation
* `PBTT_PUBLISH` : Publish operation

Refer to the API docs for a complete list of operations supported by the SDK.

### Calling patterns

This SDK provides `sync` and `callback` (notification) interfaces for retrieving the outcome of a Pubnub request/transaction/operation.

#### Sync

The `sync` interface works like this:

1. Start a transaction (say, publish - using `pubnub_publish()`)
2. Either `pubnub_await()` the outcome, or use your own loop in which you check `if (PNR_STARTED != pubnub_last_result())`
3. Handle the outcome as you wish

This is illustrated in the `Hello World` example below (which is the same for any platform that supports `sync` interface).

#### Callback

The `callback` interface is somewhat more flexible, uses less CPU resources, but is, in general, a little harder to use. One way to use it is to emulate the `sync` interface:

1. Create a callback function (`my_callback`) per the prototype required by `pubnub_register_callback()`
2. In `my_callback()`, use a condition variable to signal that outcome was received
3. Set the callback via `pubnub_register_callback()`
4. Start a transaction (say, publish - using `pubnub_publish()`)
5. Wait on the condition variable (the same one used in `my_callback`)
6. Handle the outcome as you wish

This is illustrated in the `Hello World` example below, using pthreads condition variable. Obviously, on platforms that don't support pthreads you will use some similar API (for example, SetEvent/WaitForSingleObject on Windows).

There are other ways to use the callback interface, like the `state machine` or similar, where the callback will handle the outcome of a transaction but will also start the next Pubnub transaction, or do other stuff that it needs to do. This is very application specific, so we don't provide an example here.

:::note Required UUID
Always set the `UUID` to uniquely identify the user or device that connects to PubNub. This `UUID` should be persisted, and should remain unchanged for the lifetime of the user or the device. If you don't set the `UUID`, you won't be able to connect to PubNub.
:::

```cpp
// Sync version
#include "pubnub.hpp"
#include <iostream>
const std::string channel("hello_world");

void hello_world() {
  enum pubnub_res res;
  enum pubnub_res res2;

  pubnub::context pn("", "demo");
  pubnub::context pn2("demo", "demo");
  std::string uuid("myUniqueUUID");
  pn.set_uuid(uuid);

  int loop = 0;

  std::cout << "Subscribing..." << std::endl;

  for (;;) {
    res = pn.subscribe(channel).await();

    if (PNR_OK == res) {
      std::vector<std::string> msg = pn.get_all();
      for (std::vector<std::string>::iterator it = msg.begin(); it != msg.end(); ++it) {
        std::cout << *it << std::endl;
      }

      if (++loop == 1) {
        std::cout << "Publishing..." << std::endl;

        res2 = pn2.publish(channel, "\"Hello from PubNub Docs!\"").await();

        if (PNR_OK == res2 || PNR_PUBLISH_FAILED == res2) {
          std::cout << pn2.last_publish_result() << std::endl;
        }
      }
    } else {
      std::cout << "Error" << std::endl;
      break;
    }
  }
}
```

```cpp
// Lambdas version
#include "pubnub.hpp"

#include <iostream>

const std::string channel("hello_world");

void publish() {
  pubnub_res res;

  pubnub::context pn("demo", "demo");
  res = pn.publish(channel, "\"Hello from PubNub Docs!\"").await();

  if (PNR_OK == res || PNR_PUBLISH_FAILED == res) {
    std::cout << pn.last_publish_result() << std::endl;
  }
}

int main() {
  pubnub::context ipn("", "demo");

  bool done = false;
  bool first = true;

  while (!done) {
    ipn.subscribe(channel).then([&](https://www.pubnub.com/docs/pubnub::context &pn, pubnub_res res) {
      if (PNR_OK == res) {
        if (first) {
          publish();
          first = false;
        }

        auto msg = pn.get_all();

        for (auto &&m: msg) {
          std::cout << m << std::endl;
        }

        if (msg.size() > 0) {
          done = true;
        }
      } else {
        std::cout << "Error" << std::endl;
      }
    });
  }

  return 0;
}
```

```cpp
// Functions version
#include "pubnub.hpp"
#include <iostream>

const std::string channel("hello_world");
static bool done = false;
static bool first = true;

static void on_publish(pubnub::context &pn, pubnub_res res) {
  if (PNR_OK == res || PNR_PUBLISH_FAILED == res) {
    std::cout << pn.last_publish_result() << std::endl;
  }
}

void on_subscribe(pubnub::context &pn, pubnub_res res) {
  if (first) {
    pubnub::context ppn("demo", "demo");
    ppn.publish(channel, "\"Hello from PubNub Docs!\"").then(on_publish);

    first = false;
  }

  if (PNR_OK == res) {
    std::vector<std::string> msg = pn.get_all();

    for (std::vector<std::string>::iterator it = msg.begin(); it != msg.end(); ++it) {
      std::cout << *it << std::endl;
    }

    if (msg.size() > 0) {
      done = true;
    }
  } else {
    std::cout << "Error" << std::endl;
  }
}

int main() {
  pubnub::context pn("", "demo");

  while (!done) {
    pn.subscribe(channel).then(on_subscribe);
  }
}
```

## Copy and paste examples

In addition to the Hello World sample code, we also provide some copy and paste snippets of common API functions:

### Init

Instantiate a new Pubnub instance. Only the `subscribe_key` is mandatory. Also include `publish_key` if you intend to publish from this instance, and the `secret_key` if you wish to perform Access Manager administrative operations from this Windows C++ instance.

:::note Secure your secret_key
It is not a best practice to include the secret key in client-side code for security reasons.
When you init with `secret_key`, you get root permissions for the Access Manager. With this feature you don't have to grant access to your servers to access channel data. The servers get all access on all channels.
:::

:::note Required UUID
Always set the `UUID` to uniquely identify the user or device that connects to PubNub. This `UUID` should be persisted, and should remain unchanged for the lifetime of the user or the device. If you don't set the `UUID`, you won't be able to connect to PubNub.
:::

```cpp
pubnub::context pn("my_pubkey", "my_subkey");
std::string uuid("myUniqueUUID");
pn.set_uuid(uuid);
```

### Subscribe

Subscribe (listen on) a channel (it's async!):

:::note Message retrieval
Typically, you will want two separate contexts for publish and subscribe anyway. If you are changing the set of channels you subscribe to, you should first call `leave()` on the old set.
The `subscribe()` interface is essentially a transaction to start listening on the channel for arrival of next message. This has to be followed by a call to the method `get()` or `get_all( )` to retrieve the actual message, once the subscribe transaction completes successfully. This needs to be performed every time it is desired to retrieve a message from the channel.
:::

```cpp
// Sync
void subscribe(pubnub::context &pn) {
  enum pubnub_res res;

  for (;;) {
    res = pn.subscribe("my_channel").await();

    if (PNR_OK == res) {
      std::vector<std::string> msg = pn.get_all();

      for (std::vector<std::string>::iterator it = msg.begin(); it != msg.end(); ++it) {
       std::cout << *it << std::endl;
      }
    } else {
      std::cout << "Request failed" << std::endl;
      break;
    }
  }
}
```

```cpp
// Lambdas
void subscribe(pubnub::context &ipn) {
  ipn.subscribe("my_channel").then([=](https://www.pubnub.com/docs/pubnub::context &pn, pubnub_res res) {
    auto msg = pn.get_all();

    if (PNR_OK == res) {
      for (auto &&m: msg) {
        std::cout << m << std::endl;
      }

    } else {
      std::cout << "Request failed" << std::endl;
    }
  });
}
```

```cpp
// Functions
void on_subscribe(pubnub::context &pn, pubnub_res res) {
  if (PNR_OK == res) {
    std::vector<std::string> msg = pn.get_all();

    for (std::vector<std::string>::iterator it = msg.begin(); it != msg.end(); ++it) {
      std::cout << *it << std::endl;
    }
  } else {
    std::cout << "Request failed" << std::endl;
  }
}

void subscribe(pubnub::context &pn) {
  pn.subscribe("my_channel").then(on_subscribe);
}
```

### Publish

Publish a message to a channel:

```cpp
// Sync
void publish(pubnub::context &pn) {
  enum pubnub_res res;

  res = pn.publish("my_channel", "\"Hello from the PubNub C++ SDK!\"").await();

  if (PNR_OK == res) {
    std::cout << pn.last_publish_result() << std::endl;
  } else {
    std::cout << "Publish request failed" << std::endl;
  }
}
```

```cpp
// Lambdas
void publish(pubnub::context &pn) {
  pn.publish("my_channel", "\"Hello from the PubNub C++ SDK!\"").
    then([=](https://www.pubnub.com/docs/pubnub::context &pn, pubnub_res res) {
      if (PNR_OK == res) {
        std::cout << pn.last_publish_result() << std::endl;
      } else {
        std::cout << "Publish request failed" << std::endl;
      }
    });
}
```

```cpp
// Functions
static void on_publish(pubnub::context &pn, pubnub_res res) {
  if (PNR_OK == res) {
    std::cout << pn.last_publish_result() << std::endl;
  } else {
    std::cout << "Publish request failed" << std::endl;
  }
}

void publish(pubnub::context &pn) {
  pn.publish("my_channel", "\"Hello from the PubNub C++ SDK!\"").then(on_publish);
}
```

### Here now

Get occupancy of who's `here now` on the channel by UUID:

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

```cpp
// Sync
void here_now(pubnub::context &pn) {
  enum pubnub_res res;

  res = pn.here_now("my_channel").await();

  if (PNR_OK == res) {
    std::cout << pn.get() << std::endl;
  } else {
    std::cout << "Here Now request failed" << std::endl;
  }
}
```

```cpp
// Lambdas
void here_now(pubnub::context &pn) {
  pn.here_now("my_channel").then([=](https://www.pubnub.com/docs/pubnub::context &pn, pubnub_res res) {
      if (PNR_OK == res) {
        std::cout << pn.get() << std::endl;
      } else {
        std::cout << "Here Now request failed" << std::endl;
      }
    });
}
```

```cpp
// Functions
void on_here_now(pubnub::context &pn, pubnub_res res) {
  if (PNR_OK == res) {
    std::cout << pn.get() << std::endl;
  } else {
    std::cout << "Here Now request failed" << std::endl;
  }
}

void here_now(pubnub::context &pn) {
  pn.here_now("my_channel").then(on_here_now);
}
```

### Presence

Subscribe to real-time Presence events, such as `join`, `leave`, and `timeout`, by UUID. Setting the presence attribute to a callback will subscribe to presents events on `my_channel`:

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

```cpp
// Sync
void presence(pubnub::context &pn) {
  enum pubnub_res res;
  bool done = false;

  while (!done) {
    res = pn.subscribe("my_channel-pnpres").await();

    if (PNR_OK == res) {
      std::vector<std::string> msg = pn.get_all();

      for (std::vector<std::string>::iterator it = msg.begin(); it != msg.end(); ++it) {
        std::cout << *it << std::endl;
      }

      if (msg.size() > 0) {
        done = true;
      }
    } else {
      std::cout << "Error" << std::endl;
      break;
    }
  }
}
```

```cpp
// Lambdas
void presence(pubnub::context &ipn) {
  bool done = false;

  while (!done) {
    ipn.subscribe("my_channel-pnpres").then([&](https://www.pubnub.com/docs/pubnub::context &pn, pubnub_res res) {
      auto msg = pn.get_all();

      if (PNR_OK == res) {
        for (auto &&m: msg) {
          std::cout << m << std::endl;
        }

        if (msg.size() > 0) {
          done = true;
        }
      } else {
        std::cout << "Request failed" << std::endl;
      }
    });
  }
}
```

```cpp
// Functions
void on_presence(pubnub::context &pn, pubnub_res res) {
  if (PNR_OK == res) {
    std::vector<std::string> msg = pn.get_all();

    for (std::vector<std::string>::iterator it = msg.begin(); it != msg.end(); ++it) {
      std::cout << *it << std::endl;
    }

    if (msg.size() > 0) {
      done = true;
    }
  } else {
    std::cout << "Error" << std::endl;
  }
}

void presence(pubnub::context &pn) {
  while (!done) {
    pn.subscribe("my_channel-pnpres").then(on_presence);
  }
}
```

### History

Retrieve published messages from archival storage:

:::warning Requires Message Persistence
This method requires that Message Persistence is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/).
:::

```cpp
// Sync
void history(pubnub::context &pn) {
  enum pubnub_res res;

  res = pn.history("history_channel", 100).await();;

  if (PNR_OK == res) {
    std::vector<std::string> msg = pn.get_all();

    for (std::vector<std::string>::iterator it = msg.begin(); it != msg.end(); ++it) {
      std::cout << *it << std::endl;
    }
  } else {
    std::cout << "History request failed" << std::endl;
  }
}
```

```cpp
// Lambdas
void history(pubnub::context &ipn) {
  ipn.history("history_channel").then([=](https://www.pubnub.com/docs/pubnub::context &pn, pubnub_res res) {
    auto msg = pn.get_all();

    if (PNR_OK == res) {
      for (auto &&m: msg) {
        std::cout << m << std::endl;
      }
    } else {
      std::cout << "Request failed" << std::endl;
    }
  });
}
```

```cpp
// Functions
void on_history(pubnub::context &pn, pubnub_res res) {
  if (PNR_OK == res) {
    std::vector<std::string> msg = pn.get_all();

    for (std::vector<std::string>::iterator it = msg.begin(); it != msg.end(); ++it) {
      std::cout << *it << std::endl;
    }
  } else {
    std::cout << "History request failed" << std::endl;
  }
}

void history(pubnub::context &pn) {
  pn.history("history_channel", 100).then(on_history);
}
```

### Unsubscribe

Stop subscribing (listening) to a channel.

To `unsubscribe`, you need to cancel a subscribe transaction.

* If you configured SDK to be thread-safe, you can cancel at any time, but, the cancelling may actually fail - i.e., your thread may wait for another thread to finish working with the context, and by the time your cancel request gets processed, the transaction may finish.
* If you configured SDK to not be thread-safe, the only safe way to do it is to use the sync interface and: Set the context to use non-blocking I/O, Wait for the outcome in a loop, checking for pubnub_last_result() - rather than calling pubnub_await(), If a condition occurs that prompts you to unsubscribe, call cancel(), Wait for the cancellation to finish (here you can call pubnub_await(), unless you want to do other stuff while you wait)

```cpp
auto futr = ctx.subscribe( "my_channel");
/* If we don't set non-blocking I/O, we can't get out of a blocked read */
ctx.set_blocking_io(pubnub::blocking);
/* Can't use await() here, it will block */
auto pbresult = PNR_STARTED;
while (PNR_STARTED == pbresult) {
     pbresult = futr.last_result();
     /* Somehow decide we want to quit / unsubscribe */
     if (should_stop()) {
         ctx.cancel();
         /* If we don't have anything else to do, it's OK to await now,
          * but you could again have a loop "against" pubnub_last_result()
          */
         pbresult = futr.await();
         break;
     }
}
if (PNR_CANCELLED == pbresult) {
    std::cout << "Subscribe cancelled - unsubscribed!" << std::endl;
}
```