

# Using the AWS SDK for C\$1\$1
<a name="programming-general"></a>

This section provides information about general use of the AWS SDK for C\$1\$1, beyond what is covered in [Getting Started Using the AWS SDK for C\$1\$1](getting-started.md).

For service-specific programming examples, see [AWS SDK for C\$1\$1 Code Examples](programming-services.md).

**Topics**
+ [Initializing and shutting down the SDK](basic-use.md)
+ [Making AWS service requests](using-service-client.md)
+ [Asynchronous programming](async-methods.md)
+ [Utility modules](utility-modules.md)
+ [Memory management](memory-management.md)
+ [Handling errors](error-handling.md)

# Initializing and shutting down the AWS SDK for C\$1\$1
<a name="basic-use"></a>

Applications that use the AWS SDK for C\$1\$1 must initialize it. Similarly, before the application terminates, the SDK must be shut down. Both operations accept configuration options that affect the initialization and shutdown processes and subsequent calls to the SDK.

All applications that use the AWS SDK for C\$1\$1 must include the file `aws/core/Aws.h`.

The AWS SDK for C\$1\$1 must be initialized by calling `Aws::InitAPI`. Before the application terminates, the SDK must be shut down by calling `Aws::ShutdownAPI`. Each method accepts an argument of [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). All other calls to the SDK can be performed between these two method calls.

**All AWS SDK for C\$1\$1 calls performed between `Aws::InitAPI` and `Aws::ShutdownAPI` should either to be contained within a pair of curly braces or should be invoked by functions called between the two methods.**

A basic skeleton application is shown below.

```
#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;
}
```

**The SDK for C\$1\$1 and its dependencies use C\$1\$1 static objects, and the order of static object destruction is not determined by the C\$1\$1 standard. To avoid memory issues caused by the nondeterministic order of static variable destruction, do not wrap the calls to `Aws::InitAPI` and `Aws::ShutdownAPI` into another static object. **

# Making AWS service requests using the AWS SDK for C\$1\$1
<a name="using-service-client"></a>

 To programmatically access AWS services, SDKs use a client class for each AWS service. For example, if your application needs to access Amazon EC2, your application creates an Amazon EC2 client object to interface with that service. You then use the service client to make requests to that AWS service. 

To make a request to an AWS service, you must first create and [configure](configuring.md) a service client. For each AWS service your code uses, it has its own library and its own dedicated type for interacting with it. The client exposes one method for each API operation exposed by the service. 

The namespace for a client class follows the convention `Aws::Service::ServiceClient`. For example, the client class for AWS Identity and Access Management (IAM) is `Aws::IAM::IAMClient` and the Amazon S3 client class is `Aws::S3::S3Client`.

All client classes for all AWS services are thread-safe.

When instantiating a client class, AWS credentials must be supplied. Credentials can be supplied from your code, the environment, or the shared AWS `config` file and shared `credentials` file. For more information about credentials, see [instructions for setting up the recommended IAM Identity Center authentication](credentials.md) or use [another credential provider that is available](credproviders.md).

# Asynchronous programming using the AWS SDK for C\$1\$1
<a name="async-methods"></a>

## Asynchronous SDK methods
<a name="asynchronous-sdk-methods"></a>

For many methods, the SDK for C\$1\$1 provides both synchronous and asynchronous versions. A method is asynchronous if it includes the `Async` suffix in its name. For example, the Amazon S3 method `PutObject` is synchronous, while `PutObjectAsync` is asynchronous.

Like all asynchronous operations, an asynchronous SDK method returns before its main task is finished. For example, the `PutObjectAsync` method returns before it finishes uploading the file to the Amazon S3 bucket. While the upload operation continues, the application can perform other operations, including calling other asynchronous methods. The application is notified that an asynchronous operation has finished when an associated callback function is invoked.

The following sections describe a code example that demonstrates calling the `PutObjectAsync` asynchronous method. Each section focuses on individual portions from the example’s [entire source file](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp/example_code/s3/put_object_async.cpp).

## Calling SDK asynchronous methods
<a name="calling-sdk-asynchronous-methods"></a>

In general, the asynchronous version of an SDK method accepts the following arguments.
+ A reference to the same Request-type object as its synchronous counterpart.
+ A reference to a response handler callback function. This callback function is invoked when the asynchronous operation finishes. One of the arguments contains the operation’s outcome.
+ An optional `shared_ptr` to an `AsyncCallerContext` object. The object is passed to the response handler callback. It includes a UUID property that can be used to pass text information to the callback.

The `uploadFileAsync` method shown below sets up and calls the SDK's Amazon S3 `PutObjectAsync` method to asynchronously upload a file to an Amazon S3 bucket.

The function receives references to an `S3Client` object and a `PutObjectRequest` object. It receives them from the main function because we need to ensure that these objects exist throughout the duration of the asynchronous calls.

A `shared_ptr` to an `AsyncCallerContext` object is allocated. Its `UUID` property is set to the Amazon S3 object name. For demonstration purposes, the response handler callback accesses the property and outputs its value.

The call to `PutObjectAsync` includes a reference argument to the response handler callback function `uploadFileAsyncFinished`. This callback function is examined in more detail in the next section.

```
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;
}
```

The resources for an asynchronous operation must exist until the operation finishes. For example, the client and request objects must exist until the application receives notification that the operation completed. The application itself cannot terminate until the asynchronous operation completes.

For this reason, the `uploadFileAsync` method accepts a references to `S3Client` and `PutObjectRequest` objects instead of creating them in the `uploadFileAsync` method and storing them in a local variable. 

In the example, the `PutObjectAsync` method returns to the caller immediately after beginning the asynchronous operation, enabling the calling chain to perform additional tasks while the upload operation is in progress. 

If the client were stored in a local variable in the `uploadFileAsync` method, it would go out of scope when the method returned. However, the client object must continue to exist until the asynchronous operation finishes.

## Notification of the Completion of an Asynchronous Operation
<a name="notification-of-the-completion-of-an-asynchronous-operation"></a>

When an asynchronous operation finishes, an application response handler callback function is invoked. This notification includes the outcome of the operation. The outcome is contained in the same Outcome-type class returned by the method’s synchronous counterpart. In the code example, the outcome is in a `PutObjectOutcome` object.

The example’s response handler callback function `uploadFileAsyncFinished` is shown below. It checks whether the asynchronous operation succeeded or failed. It uses a `std::condition_variable` to notify the application thread that the async operation has finished.

```
// 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();
}
```

With the asynchronous operation finished, the resources associated with it can be released. The application can also terminate if it wishes.

The following code demonstrates how the `uploadFileAsync` and `uploadFileAsyncFinished` methods are used by an application.

The application allocates the `S3Client` and `PutObjectRequest` objects so that they continue to exist until the asynchronous operation finishes. After calling `uploadFileAsync`, the application can perform whatever operations it wishes. For simplicity, the example uses a `std::mutex` and `std::condition_variable` to wait until the response handler callback notifies it that the upload operation has finished.

```
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;
}
```

See the [complete example](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp/example_code/s3/put_object_async.cpp) on Github.

# Utility modules available in the AWS SDK for C\$1\$1
<a name="utility-modules"></a>

The AWS SDK for C\$1\$1 includes many [utility modules](https://docs.aws.amazon.com/sdk-for-cpp/latest/api/aws-cpp-sdk-core/html/namespace_aws_1_1_utils.html) to reduce the complexity of developing AWS applications in C\$1\$1.

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

An HTTP stack that provides connection pooling, is thread-safe, and can be reused as you need. For more information, see [AWS Client Configuration](client-config.md).


****  

|  |  | 
| --- |--- |
|  Headers  |   [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 Documentation  |   [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)   | 

## String Utils
<a name="string-utils"></a>

Core string functions, such as `trim`, `lowercase`, and numeric conversions.


****  

|  |  | 
| --- |--- |
|  Header  |   [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 Documentation  |   [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)   | 

## Hashing Utils
<a name="hashing-utils"></a>

Hashing functions such as `SHA256`, `MD5`, `Base64`, and `SHA256_HMAC`.


****  

|  |  | 
| --- |--- |
|  Header  |   [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 Documentation  |   [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 Parser
<a name="json-parser"></a>

A fully functioning yet lightweight JSON parser (a thin wrapper around *`cJSON`*).


****  

|  |  | 
| --- |--- |
|  Header  |   [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 Documentation  |   [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 Parser
<a name="xml-parser"></a>

A lightweight XML parser (a thin wrapper around *`tinyxml2`*). The [RAII pattern](http://en.cppreference.com/w/cpp/language/raii) has been added to the interface.


****  

|  |  | 
| --- |--- |
|  Header  |   [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 Documentation  |   [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)   | 

# Memory management in the the AWS SDK for C\$1\$1
<a name="memory-management"></a>

The AWS SDK for C\$1\$1 provides a way to control memory allocation and deallocation in a library.

**Note**  
Custom memory management is available only if you use a version of the library built using the defined compile-time constant `USE_AWS_MEMORY_MANAGEMENT`.  
If you use a version of the library that is built without the compile-time constant, global memory system functions such as `InitializeAWSMemorySystem` won’t work; the global `new` and `delete` functions are used instead.

For more information about the compile-time constant, see [STL and AWS Strings and Vectors](#stl-and-aws-strings-and-vectors).

## Allocating and Deallocating Memory
<a name="allocating-and-deallocating-memory"></a>

 **To allocate or deallocate memory** 

1. Subclass `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;
   };
   ```
**Note**  
You can change the type signature for `AllocateMemory` as needed.

1. Use the `Aws::SDKOptions` struct to configure the use of the custom memory manager. Pass the instance of the struct into `Aws::InitAPI`. Before the application terminates, the SDK must be shut down by calling `Aws::ShutdownAPI` with the same instance. 

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

## STL and AWS Strings and Vectors
<a name="stl-and-aws-strings-and-vectors"></a>

When initialized with a memory manager, the AWS SDK for C\$1\$1 defers all allocation and deallocation to the memory manager. If a memory manager doesn’t exist, the SDK uses global new and delete.

If you use custom STL allocators, you must alter the type signatures for all STL objects to match the allocation policy. Because STL is used prominently in the SDK implementation and interface, a single approach in the SDK would inhibit direct passing of default STL objects into the SDK or control of STL allocation. Alternately, a hybrid approach—using custom allocators internally and allowing standard and custom STL objects on the interface—could potentially make it more difficult to investigate memory issues.

The solution is to use the memory system’s compile-time constant `USE_AWS_MEMORY_MANAGEMENT` to control which STL types the SDK uses.

If the compile-time constant is enabled (on), the types resolve to STL types with a custom allocator connected to the AWS memory system.

If the compile-time constant is disabled (off), all `Aws::*` types resolve to the corresponding default `std::*` type.

 **Example code from the `AWSAllocator.h` file in the SDK** 

```
#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
```

In the example code, the `AwsAllocator` can be a custom allocator or a default allocator, depending on the compile-time constant.

 **Example code from the `AWSVector.h` file in the SDK** 

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

In the example code, we define the `Aws::*` types.

If the compile-time constant is enabled (on), the type maps to a vector using custom memory allocation and the AWS memory system.

If the compile-time constant is disabled (off), the type maps to a regular `std::vector` with default type parameters.

Type aliasing is used for all `std::` types in the SDK that perform memory allocation, such as containers, string streams, and string buffers. The AWS SDK for C\$1\$1 uses these types.

## Remaining Issues
<a name="remaining-issues"></a>

You can control memory allocation in the SDK; however, STL types still dominate the public interface through string parameters to the model object `initialize` and `set` methods. If you don’t use STL and use strings and containers instead, you have to create a lot of temporaries whenever you want to make a service call.

To remove most of the temporaries and allocation when you make service calls using non-STL, we have implemented the following:
+ Every Init/Set function that takes a string has an overload that takes a `const char*`.
+ Every Init/Set function that takes a container (map/vector) has an add variant that takes a single entry.
+ Every Init/Set function that takes binary data has an overload that takes a pointer to the data and a `length` value.
+ (Optional) Every Init/Set function that takes a string has an overload that takes a non-zero terminated `const char*` and a `length` value.

## Native SDK Developers and Memory Controls
<a name="native-sdk-developers-and-memory-controls"></a>

Follow these rules in the SDK code:
+ Don’t use `new` and `delete`; use `Aws::New<>` and `Aws::Delete<>` instead.
+ Don’t use `new[]` and `delete[]`; use `Aws::NewArray<>` and `Aws::DeleteArray<>`.
+ Don’t use `std::make_shared`; use `Aws::MakeShared`.
+ Use `Aws::UniquePtr` for unique pointers to a single object. Use the `Aws::MakeUnique` function to create the unique pointer.
+ Use `Aws::UniqueArray` for unique pointers to an array of objects. Use the `Aws::MakeUniqueArray` function to create the unique pointer.
+ Don’t directly use STL containers; use one of the `Aws::` typedefs or add a typedef for the container you want. For example:

  ```
  Aws::Map<Aws::String, Aws::String> m_kvPairs;
  ```
+ Use `shared_ptr` for any external pointer passed into and managed by the SDK. You must initialize the shared pointer with a destruction policy that matches how the object was allocated. You can use a raw pointer if the SDK is not expected to clean up the pointer.

# Handling errors in the AWS SDK for C\$1\$1
<a name="error-handling"></a>

The AWS SDK for C\$1\$1 does not use exceptions; however, you can use exceptions in your code. Every service client returns an outcome object that includes the result and an error code.

 **Example of handling error conditions** 

```
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;
}
```