29 Mart 2019 Cuma

std::string c_str() Metodu

Giriş
İmzası şöyle.
const charT* c_str() const noexcept;
Bu metod null terminated bir bellek alanı döner.

Açıklaması şöyle.
The pointer obtained from c_str() may be invalidated by:
  • Passing a non-const reference to the string to any standard library function, or
  • Calling non-const member functions on the string, excluding operator[], at(), front(), back(), begin(), rbegin(), end() and rend().
Prvalue std::string ve c_str() metodu
Bir metodun içindeki temporary std::string'den c_str() kullanarak bellek döndürmemek gerekir. Açıklaması şöyle.
data points to an internal of that object, so after the temporary ends you are left with a dangling pointer. Accessing it leads to Undefined Behavior.
Görsel olarak şöyle.
const char* data = get_data().c_str() ;
//                 ^~~~~~~~~~         ^
//                 this evaluates     |
//                 to a prvalue       |
//                                    temporary expires here
Doğru kullanım şöyle.
int main()
{
  const std::string& ref = get_data();
  const char* data = ref.c_str();
  std::cout << data << "\n";
  return 0;
}
Şu kod yanlış.
#include <iostream>

std::string get_data()
{
    return "Hello";
}

int main()
{
    const char* data = get_data().c_str();
    std::cout << data << "\n";
    return 0;
}
Şu kod yanlış.
const char *returnMsg(const char *msg)
{
  static std::string message;

  message = msg;

  return message.c_str();
}

int main(int argc, char *argv[])
{
  const char *msg1 = returnMsg("Hello world");
  printf("msg1 = %p\n", msg1);
  cout << msg1 << endl;

  const char *msg2 = returnMsg("Good bye");
  printf("msg2 = %p\n", msg2);
  cout << msg2 << endl;

  cout << msg1 << endl; //Burada msg1 artık geçersiz hale geliyor.

  return 0;
}

28 Mart 2019 Perşembe

std::shared_ptr Sınıfı - Aliasing Constructor

Giriş
Metodun imzası şöyle.
template <class U> shared_ptr (const shared_ptr<U>& r, element_type* p) noexcept;
Açıklaması şöyle
Effects: Constructs a shared_ptr instance that stores p and shares ownership with r.
p'yi kullanırken r'nin yok olmamasını sağlar. r shared_ptr olmalıdır. get() metodu yine p'yi döndürür.

p için no-op deleter yazmak yerine aliasing constructor kullanılabilir.

Örnek
Örneğin connection üreten bir factor sınıfımız olsun. Connection'ı kullandığımız müddetçe factory nesnesinin de yok olmaması gerekir. Bu durumda r = factory, p = connection olarak kullanılır. Şöyle yaparız.
class Factory : public std::enable_shared_from_this<Factory>
{
public:
    
  std::shared_ptr<Connection> getConnection()
  {
    return shared_ptr<Value>(shared_from_this(), new Connection());  }
};
Factory sınıfının shared_ptr olarak ilklendirilmesi gerekir.
auto factory = std::make_shared<Factory>();
Şöyle çağırırız.
shared_ptr<Connection> pCon;
{
    // Factory needs to be managed by a shared_ptr.
    auto factory = std::make_shared<Factory>();

    // factory can go out of scope
    // the Factory will be kept alive as long as pCon is alive
    pCon = factory->getConnection();
}
Örnek
Elimizde bir shared_ptr dizisi olsun.
std::shared_ptr<int> sp(new T[10], [](T *p) { delete[] p; });
Bu dizi içindeki int'e indeks ile erişirken sp'nin yok olmamasını isteyelim. Şöyle yaparız.
shared_ptr<T> ptr_at_offset(int offset) {
  return {sp, sp.get() + offset};
}
Örnek
Elimizdeki shared_ptr buffer nesnesini offset ile kullanmak isteyelim. Böylece ilk nesne kaybolmadan ikinci nesne yine aynı buffer'daki farklı bir yere işaret eder. Şöyle yaparız.
// make sure you use an array deleter
std::shared_ptr<char> osp(new char[1024], std::default_delete<char[]>());

// load the data into your buffer at osp.get()

// Find the offset in the data by parsing
auto const offset = parse_buffer_for_offset(osp.get());

// Now set a new offset into the data
std::shared_ptr<char> nsp(osp, osp.get() + offset);