

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用适用于 C\$1\$1 的 S AWS DK
<a name="programming-general"></a>

除了[入门使用中介绍的内容之外 适用于 C\$1\$1 的 AWS SDK，本节还提供有关一般用法](getting-started.md)的信息 适用于 C\$1\$1 的 AWS SDK。

有关特定服务的编程示例，请参阅[适用于 C\$1\$1 的 AWS SDK 代码示例](programming-services.md)。

**Topics**
+ [初始化和关闭 SDK](basic-use.md)
+ [提出 AWS 服务请求](using-service-client.md)
+ [异步编程](async-methods.md)
+ [实用程序模块](utility-modules.md)
+ [内存管理](memory-management.md)
+ [处理错误](error-handling.md)

# 初始化和关闭 适用于 C\$1\$1 的 AWS SDK
<a name="basic-use"></a>

使用适用于 C\$1\$1 的 AWS SDK 的应用程序必须将其初始化。同样，在应用程序终止之前，必须先关闭 SDK。这两个操作都接受影响初始化和关闭进程以及随后对 SDK 的调用的配置选项。

所有使用适用于 C\$1\$1 的 AWS SDK 的应用程序都必须包含 `aws/core/Aws.h` 文件。

适用于 C\$1\$1 的 AWS SDK 必须通过调用 `Aws::InitAPI` 进行初始化。在应用程序终止之前，必须通过调用 `Aws::ShutdownAPI` 关闭 SDK。每个方法都接受 [https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/struct_aws_1_1_s_d_k_options.html](https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/struct_aws_1_1_s_d_k_options.html) 的一个参数。对 SDK 的所有其他调用都可以在这两个方法调用之间执行。

**所有在 `Aws::InitAPI` 和 `Aws::ShutdownAPI` 之间执行的适用于 C\$1\$1 的 AWS SDK 调用，要么包含在一对花括号内，要么通过这两个方法之间被调用的函数来发起。**

下面显示了一个基本骨架应用程序。

```
#include <aws/core/Aws.h>
int main(int argc, char** argv)
{
   Aws::SDKOptions options;
   Aws::InitAPI(options);
   {
      // make your SDK calls here.
   }
   Aws::ShutdownAPI(options);
   return 0;
}
```

**适用于 C\$1\$1 的 SDK 及其依赖项使用 C\$1\$1 静态对象，静态对象的销毁顺序不由 C\$1\$1 标准决定。为避免静态变量销毁顺序的不确定性导致内存问题，请勿将对 `Aws::InitAPI` 和 `Aws::ShutdownAPI` 的调用封装到另一个静态对象中。**

# 使用适用于 C\$1\$1 的 AWS SDK 发出 AWS 服务请求
<a name="using-service-client"></a>

 要以编程方式访问 AWS 服务，SDK 对每个 AWS 服务使用一个客户端类。例如，如果您的应用程序需要访问 Amazon EC2，则您的应用程序会创建一个 Amazon EC2 客户端对象来与该服务交互。然后，您可以使用服务客户端向该 AWS 服务 发出请求。

要向 AWS 服务发出请求，您必须先创建和[配置](configuring.md)服务客户端。对于您的代码使用的每个 AWS 服务，它都有自己的库和用于与之交互的专用类型。客户端为服务公开的每个 API 操作公开一种方法。

客户端类的命名空间遵循惯例 `Aws::Service::ServiceClient`。例如，AWS Identity and Access Management（IAM）的客户端类是 `Aws::IAM::IAMClient`，Amazon S3 的客户端类是 `Aws::S3::S3Client`。

所有 AWS 服务的所有客户端类都是线程安全的。

实例化客户端类时，必须提供 AWS 凭证。可以通过您的代码、环境或共享 AWS `config` 文件及共享 `credentials` 文件提供凭证。有关凭证的更多信息，请参阅[设置推荐的 IAM Identity Center 身份验证的说明](credentials.md)或使用[其他可用的凭证提供程序](credproviders.md)。

# 异步编程使用 适用于 C\$1\$1 的 AWS SDK
<a name="async-methods"></a>

## 异步 SDK 方法
<a name="asynchronous-sdk-methods"></a>

对于许多方法，适用于 C\$1\$1 的 SDK 同时提供同步和异步版本。如果方法的名称中包含 `Async` 后缀，则该方法是异步的。例如，Amazon S3 方法 `PutObject` 是同步的，而 `PutObjectAsync` 是异步的。

与所有异步操作一样，异步 SDK 方法会在主任务完成之前返回。例如，`PutObjectAsync` 方法会在将文件上传到 Amazon S3 存储桶之前返回。文件上传操作持续进行期间，应用程序可执行其他操作，包括调用其他异步方法。调用关联的回调函数时，应用程序会收到异步操作已完成的通知。

以下各节描述了一个演示调用 `PutObjectAsync` 异步方法的代码示例。每节会重点介绍该示例[整个源文件](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp/example_code/s3/put_object_async.cpp)中的各个部分。

## 调用 SDK 异步方法
<a name="calling-sdk-asynchronous-methods"></a>

通常，SDK 方法的异步版本接受以下参数。
+ 对与同步版本对应的同一 Request 类型对象的引用。
+ 对响应处理程序回调函数的引用。当异步操作完成时，将调用此回调函数。其中一个参数包含操作的结果。
+ `AsyncCallerContext` 对象的可选 `shared_ptr`。该对象被传递给响应处理程序回调。它包含一个 UUID 属性，可用于将文本信息传递给回调。

下面显示的 `uploadFileAsync` 方法设置并调用 SDK 的 Amazon S3 `PutObjectAsync` 方法，以异步方式将文件上传到 Amazon S3 存储桶。

该函数接收对 `S3Client` 对象和 `PutObjectRequest` 对象的引用。这些对象由主函数传入，因为我们需要确保它们在异步调用的整个执行期间始终存在。

分配一个指向 `AsyncCallerContext` 对象的 `shared_ptr`。其 `UUID` 属性设置为 Amazon S3 对象名称。出于演示目的，响应处理程序回调会访问该属性并输出其值。

对 `PutObjectAsync` 的调用包括响应处理程序回调函数 `uploadFileAsyncFinished` 的引用参数。下一节将更详细地讨论这一回调函数。

```
bool AwsDoc::S3::uploadFileAsync(const Aws::S3::S3Client &s3Client,
                                Aws::S3::Model::PutObjectRequest &request,
                                const Aws::String &bucketName,
                                const Aws::String &fileName) {
    request.SetBucket(bucketName);
    request.SetKey(fileName);

    const std::shared_ptr<Aws::IOStream> input_data =
            Aws::MakeShared<Aws::FStream>("SampleAllocationTag",
                                          fileName.c_str(),
                                          std::ios_base::in | std::ios_base::binary);

    if (!*input_data) {
        std::cerr << "Error: unable to open file " << fileName << std::endl;
        return false;
    }

    request.SetBody(input_data);

    // Create and configure the context for the asynchronous put object request.
    std::shared_ptr<Aws::Client::AsyncCallerContext> context =
            Aws::MakeShared<Aws::Client::AsyncCallerContext>("PutObjectAllocationTag");
    context->SetUUID(fileName);

    // Make the asynchronous put object call. Queue the request into a 
    // thread executor and call the uploadFileAsyncFinished function when the
    // operation has finished. 
    s3Client.PutObjectAsync(request, uploadFileAsyncFinished, context);

    return true;
}
```

在操作完成之前，用于异步操作的资源必须存在。例如，在应用程序收到操作完成的通知之前，客户端和请求对象必须存在。在异步操作完成之前，应用程序本身无法终止。

因此，`uploadFileAsync` 方法接受对 `S3Client` 和 `PutObjectRequest` 对象的引用，而不是在 `uploadFileAsync` 方法中创建它们并将其存储在局部变量中。

在该示例中，`PutObjectAsync` 方法启动异步操作后会立即向调用方返回，使得调用链能够在上传操作执行期间执行其他任务。

如果客户端存储在 `uploadFileAsync` 方法的局部变量中，那么该对象会在方法返回时超出范围。但是，在异步操作完成之前，客户端对象必须继续存在。

## 异步操作完成通知
<a name="notification-of-the-completion-of-an-asynchronous-operation"></a>

异步操作完成后，将调用应用程序响应处理程序回调函数。此通知包括操作结果。操作结果包含在该方法同步版本返回的同一 Outcome 类型类中。在代码示例中，结果位于 `PutObjectOutcome` 对象中。

下面显示了该示例的响应处理程序回调函数 `uploadFileAsyncFinished`。它会检查异步操作是成功还是失败。它使用 `std::condition_variable` 通知应用程序线程异步操作已完成。

```
// A mutex is a synchronization primitive that can be used to protect shared
// data from being simultaneously accessed by multiple threads.
std::mutex AwsDoc::S3::upload_mutex;

// A condition_variable is a synchronization primitive that can be used to
// block a thread, or to block multiple threads at the same time.
// The thread is blocked until another thread both modifies a shared
// variable (the condition) and notifies the condition_variable.
std::condition_variable AwsDoc::S3::upload_variable;
```

```
void uploadFileAsyncFinished(const Aws::S3::S3Client *s3Client,
                            const Aws::S3::Model::PutObjectRequest &request,
                            const Aws::S3::Model::PutObjectOutcome &outcome,
                            const std::shared_ptr<const Aws::Client::AsyncCallerContext> &context) {
    if (outcome.IsSuccess()) {
        std::cout << "Success: uploadFileAsyncFinished: Finished uploading '"
                  << context->GetUUID() << "'." << std::endl;
    } else {
        std::cerr << "Error: uploadFileAsyncFinished: " <<
                  outcome.GetError().GetMessage() << std::endl;
    }

    // Unblock the thread that is waiting for this function to complete.
    AwsDoc::S3::upload_variable.notify_one();
}
```

异步操作完成后，可以释放与其关联的资源。如果愿意，应用程序也可以终止这些资源。

以下代码演示了应用程序如何使用 `uploadFileAsync` 和 `uploadFileAsyncFinished` 方法。

应用程序分配 `S3Client` 和 `PutObjectRequest` 对象，以便它们在异步操作完成之前持续存在。调用 `uploadFileAsync` 后，应用程序可以执行它想要执行的任何操作。为了简单起见，该示例使用 `std::mutex` 和 `std::condition_variable` 进行等待，直至响应处理程序回调通知上传操作已完成。

```
int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        std::cout << R"(
Usage:
    run_put_object_async <file_name> <bucket_name>
Where:
    file_name - The name of the file to upload.
    bucket_name - The name of the bucket to upload the object to.
)" << std::endl;
        return 1;
    }

    const Aws::SDKOptions options;
    Aws::InitAPI(options);
    {
        const Aws::String fileName = argv[1];
        const Aws::String bucketName = argv[2];

        // A unique_lock is a general-purpose mutex ownership wrapper allowing
        // deferred locking, time-constrained attempts at locking, recursive
        // locking, transfer of lock ownership, and use with
        // condition variables.
        std::unique_lock<std::mutex> lock(AwsDoc::S3::upload_mutex);

        // Create and configure the Amazon S3 client.
        // This client must be declared here, as this client must exist
        // until the put object operation finishes.
        const Aws::S3::S3ClientConfiguration config;
        // Optional: Set to the AWS Region in which the bucket was created (overrides config file).
        // config.region = "us-east-1";

        const Aws::S3::S3Client s3Client(config);

        // Create the request object.
        // This request object must be declared here, because the object must exist
        // until the put object operation finishes.
        Aws::S3::Model::PutObjectRequest request;

        AwsDoc::S3::uploadFileAsync(s3Client, request, bucketName, fileName);

        std::cout << "main: Waiting for file upload attempt..." <<
                  std::endl << std::endl;

        // While the put object operation attempt is in progress,
        // you can perform other tasks.
        // This example simply blocks until the put object operation
        // attempt finishes.
        AwsDoc::S3::upload_variable.wait(lock);

        std::cout << std::endl << "main: File upload attempt completed."
                  << std::endl;
    }
    Aws::ShutdownAPI(options);

    return 0;
}
```

请参阅 [Github](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp/example_code/s3/put_object_async.cpp) 上的完整示例。

# 适用于 C\$1\$1 的 AWS SDK 中提供的实用程序模块
<a name="utility-modules"></a>

适用于 C\$1\$1 的 AWS SDK 包括许多[实用程序模块](https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/namespace_aws_1_1_utils.html)，用于降低使用 C\$1\$1 开发 AWS 应用程序的复杂性。

## HTTP 堆栈
<a name="http-stack"></a>

提供连接池的 HTTP 堆栈是线程安全的，可以根据需要重用。有关更多信息，请参阅[AWS 客户端配置](client-config.md)。


****  

|  |  | 
| --- |--- |
|  标头  |   [https://github.com/aws/aws-sdk-cpp/tree/master/aws-cpp-sdk-core/include/aws/core/http](https://github.com/aws/aws-sdk-cpp/tree/master/aws-cpp-sdk-core/include/aws/core/http)   | 
|  API 文档  |   [https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/namespace_aws_1_1_http.html](https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/namespace_aws_1_1_http.html)   | 

## 字符串实用程序
<a name="string-utils"></a>

核心字符串函数，例如 `trim`、`lowercase` 和数字转换。


****  

|  |  | 
| --- |--- |
|  标题  |   [https://github.com/aws/aws-sdk-cpp/tree/master/aws-cpp-sdk-core/include/aws/core/utils/StringUtils.h](https://github.com/aws/aws-sdk-cpp/tree/master/aws-cpp-sdk-core/include/aws/core/utils/StringUtils.h)   | 
|  API 文档  |   [https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/class_aws_1_1_utils_1_1_string_utils.html](https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/class_aws_1_1_utils_1_1_string_utils.html)   | 

## 哈希实用程序
<a name="hashing-utils"></a>

哈希函数，例如 `SHA256`、`MD5`、`Base64` 和 `SHA256_HMAC`。


****  

|  |  | 
| --- |--- |
|  标题  |   [https://github.com/aws/aws-sdk-cpp/tree/master/aws-cpp-sdk-core/include/aws/core/utils/HashingUtils.h](https://github.com/aws/aws-sdk-cpp/tree/master/aws-cpp-sdk-core/include/aws/core/utils/HashingUtils.h)   | 
|  API 文档  |   [https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/class_aws_1_1_utils_1_1_hashing_utils.html](https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/class_aws_1_1_utils_1_1_hashing_utils.html)   | 

## JSON 解析器
<a name="json-parser"></a>

一个功能齐全但轻量级的 JSON 解析器（对 *`cJSON`* 的薄封装）。


****  

|  |  | 
| --- |--- |
|  标题  |   [https://github.com/aws/aws-sdk-cpp/tree/master/aws-cpp-sdk-core/include/aws/core/utils/json/JsonSerializer.h](https://github.com/aws/aws-sdk-cpp/tree/master/aws-cpp-sdk-core/include/aws/core/utils/json/JsonSerializer.h)   | 
|  API 文档  |   [https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/class_aws_1_1_utils_1_1_json_1_1_json_value.html](https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/class_aws_1_1_utils_1_1_json_1_1_json_value.html)   | 

## XML 解析器
<a name="xml-parser"></a>

一个轻量级 XML 解析器（对 *`tinyxml2`* 的一层薄封装）。[RAII 模式](http://en.cppreference.com/w/cpp/language/raii)已添加到接口中。


****  

|  |  | 
| --- |--- |
|  标题  |   [https://github.com/aws/aws-sdk-cpp/tree/master/aws-cpp-sdk-core/include/aws/core/utils/xml/XmlSerializer.h](https://github.com/aws/aws-sdk-cpp/tree/master/aws-cpp-sdk-core/include/aws/core/utils/xml/XmlSerializer.h)   | 
|  API 文档  |   [https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/namespace_aws_1_1_utils_1_1_xml.html](https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/namespace_aws_1_1_utils_1_1_xml.html)   | 

# 中的内存管理 适用于 C\$1\$1 的 AWS SDK
<a name="memory-management"></a>

 适用于 C\$1\$1 的 AWS SDK 提供了一种控制库中内存分配和取消分配的方法。

**注意**  
仅当您使用通过已定义的编译时常量 `USE_AWS_MEMORY_MANAGEMENT` 构建的库版本时，自定义内存管理功能才可用。  
如果您使用的库版本是在没有这个编译时常量的情况下构建的，那么像 `InitializeAWSMemorySystem` 这样的全局内存系统函数将不会生效；而是会使用全局 `new` 和 `delete` 函数。

有关编译时常量的更多信息，请参见 [STL 和 AWS 字符串和](#stl-and-aws-strings-and-vectors)向量。

## 分配和取消分配内存
<a name="allocating-and-deallocating-memory"></a>

 **分配或取消分配内存** 

1. 子类 `MemorySystemInterface`：`aws/core/utils/memory/MemorySystemInterface.h`。

   ```
   class MyMemoryManager : public Aws::Utils::Memory::MemorySystemInterface
   {
   public:
       // ...
       virtual void* AllocateMemory(
           std::size_t blockSize, std::size_t alignment,
           const char *allocationTag = nullptr) override;
       virtual void FreeMemory(void* memoryPtr) override;
   };
   ```
**注意**  
您可以根据需要更改 `AllocateMemory` 的类型签名。

1. 使用 `Aws::SDKOptions` 结构来配置自定义内存管理器的用法。将该结构的实例传递到 `Aws::InitAPI`。在应用程序终止之前，必须对同一个实例调用 `Aws::ShutdownAPI` 来关闭 SDK。

   ```
   int main(void)
   {
     MyMemoryManager sdkMemoryManager;
     SDKOptions options;
     options.memoryManagementOptions.memoryManager = &sdkMemoryManager;
     Aws::InitAPI(options);
   
     // ... do stuff
   
     Aws::ShutdownAPI(options);
   
     return 0;
   }
   ```

## STL 和 AWS 字符串和向量
<a name="stl-and-aws-strings-and-vectors"></a>

使用内存管理器初始化时，会将所有分配和取消分配推 适用于 C\$1\$1 的 AWS SDK 迟到内存管理器。如果内存管理器不存在，SDK 将使用全局新建和删除。

如果您使用自定义 STL 分配器，则必须更改所有 STL 对象的类型签名以匹配分配策略。由于 SDK 的实现和接口中大量使用 STL，若 SDK 采用单一实现方式，将无法直接将默认 STL 对象传入 SDK，也无法对 STL 内存分配进行控制。另一种方案是混合实现方式 — 在内部使用自定义分配器，同时允许接口使用标准 STL 对象和自定义 STL 对象，但这种方式可能会增加内存问题的排查难度。

解决方案是使用内存系统的编译时常量 `USE_AWS_MEMORY_MANAGEMENT` 来控制 SDK 使用哪些 STL 类型。

如果启用编译时常量（开启），则使用连接到内存系统的自定义分配器将类型解析为 STL 类型。 AWS 

如果禁用编译时常量（设为关闭状态），则所有 `Aws::*` 类型都解析为相应的默认 `std::*` 类型。

 **来自 SDK 中 `AWSAllocator.h` 文件的示例代码** 

```
#ifdef USE_AWS_MEMORY_MANAGEMENT

template< typename T >
class AwsAllocator : public std::allocator< T >
{
   ... definition of allocator that uses AWS memory system
};

#else

template< typename T > using Allocator = std::allocator<T>;

#endif
```

在示例代码中，`AwsAllocator` 可以是自定义分配器或默认分配器，具体取决于编译时常量。

 **来自 SDK 中 `AWSVector.h` 文件的示例代码** 

```
template<typename T> using Vector = std::vector<T, Aws::Allocator<T>>;
```

在示例代码中，我们定义 `Aws::*` 类型。

如果启用了编译时常量（开启），则该类型将使用自定义内存分配和内存系统映射到向量。 AWS 

如果禁用编译时常量（设为关闭状态），则该类型将映射到带有默认类型参数的常规 `std::vector`。

类型别名用于 SDK 中执行内存分配的所有 `std::` 类型，例如容器、字符串流和字符串缓冲区。 适用于 C\$1\$1 的 AWS SDK 使用这些类型。

## 其余问题
<a name="remaining-issues"></a>

您可以控制该 SDK 中的内存分配；然而，STL 类型仍然在公共接口中占主导地位 — 通过模型对象的 `initialize` 和 `set` 方法中的字符串参数实现。如果您不使用 STL 而是使用字符串和容器，那么每当您想进行服务调用时，都必须创建很多临时变量。

为了删除使用非 STL 进行服务调用时的大部分临时变量和内存分配，我们实现了以下内容：
+ 每个接受字符串的 Init/Set 函数都有一个重载，该重载需要一个`const char*`.
+ 每个 Init/Set 使用容器（地图/向量）的函数都有一个添加变体，该变体需要一个条目。
+ 每个接受二进制数据的 Init/Set 函数都有一个重载，它需要一个指向数据的指针和一个`length`值。
+ （可选）每个接受字符串的 Init/Set 函数都有一个重载，该重载采用非零结尾`const char*`和一个`length`值。

## 原生 SDK 开发工具和内存控件
<a name="native-sdk-developers-and-memory-controls"></a>

在 SDK 代码中遵循以下规则：
+ 不要使用 `new` 和 `delete`；而是使用 `Aws::New<>` 和 `Aws::Delete<>`。
+ 不要使用 `new[]` 和 `delete[]`；而是使用 `Aws::NewArray<>` 和 `Aws::DeleteArray<>`。
+ 不要使用 `std::make_shared`；而是使用 `Aws::MakeShared`。
+ 使用 `Aws::UniquePtr` 表示指向单个对象的唯一指针。使用 `Aws::MakeUnique` 函数创建唯一指针。
+ 使用 `Aws::UniqueArray` 表示指向对象数组的唯一指针。使用 `Aws::MakeUniqueArray` 函数创建唯一指针。
+ 不要直接使用 STL 容器；使用其中一个 `Aws::` typedef 或者为所需的容器添加一个 typedef。例如：

  ```
  Aws::Map<Aws::String, Aws::String> m_kvPairs;
  ```
+ 使用 `shared_ptr` 表示传入 SDK 并由 SDK 管理的任何外部指针。必须使用与对象分配方式相匹配的销毁策略来初始化共享指针。如果 SDK 不应该清理指针，则您可以使用原始指针。

# 处理适用于 C\$1\$1 的 AWS SDK 中的错误
<a name="error-handling"></a>

适用于 C\$1\$1 的 AWS SDK 不使用异常；不过，您可以在代码中使用异常。每个服务客户端都会返回一个包含结果和错误代码的结果对象。

 **处理错误条件的示例** 

```
bool CreateTableAndWaitForItToBeActive()
{
  CreateTableRequest createTableRequest;
  AttributeDefinition hashKey;
  hashKey.SetAttributeName(HASH_KEY_NAME);
  hashKey.SetAttributeType(ScalarAttributeType::S);
  createTableRequest.AddAttributeDefinitions(hashKey);
  KeySchemaElement hashKeySchemaElement;
  hashKeySchemaElement.WithAttributeName(HASH_KEY_NAME).WithKeyType(KeyType::HASH);
  createTableRequest.AddKeySchema(hashKeySchemaElement);
  ProvisionedThroughput provisionedThroughput;
  provisionedThroughput.SetReadCapacityUnits(readCap);
  provisionedThroughput.SetWriteCapacityUnits(writeCap);
  createTableRequest.WithProvisionedThroughput(provisionedThroughput);
  createTableRequest.WithTableName(tableName);

  CreateTableOutcome createTableOutcome = dynamoDbClient->CreateTable(createTableRequest);
  if (createTableOutcome.IsSuccess())
  {
     DescribeTableRequest describeTableRequest;
     describeTableRequest.SetTableName(tableName);
     bool shouldContinue = true;
     DescribeTableOutcome outcome = dynamoDbClient->DescribeTable(describeTableRequest);

     while (shouldContinue)
     {
         if (outcome.GetResult().GetTable().GetTableStatus() == TableStatus::ACTIVE)
         {
            break;
         }
         else
         {
            std::this_thread::sleep_for(std::chrono::seconds(1));
         }
     }
     return true;
  }
  else if(createTableOutcome.GetError().GetErrorType() == DynamoDBErrors::RESOURCE_IN_USE)
  {
     return true;
  }

  return false;
}
```