Разыменование unique_ptr к ссылке - PullRequest
2 голосов
/ 14 июня 2019

Следующий (небезопасный) код работает

#include <iostream>
#include <fstream>

std::ofstream* create_unsafe_stream(const char* filename) {
    return new std::ofstream {filename};
}

int main () {
    std::ofstream& u_out = *create_unsafe_stream("foo.txt");
    u_out << "foo\n" ;
    delete &u_out;
    return 0;
}

Я пытался создать более безопасную версию

#include <iostream>
#include <fstream>
#include <memory>

using stream_ptr = std::unique_ptr<std::ostream>;

stream_ptr create_safe_stream(const char* filename) {
    return stream_ptr{ new std::ofstream {filename}};
}

int main() {
  std::ostream& s_out = *create_safe_stream("foo.txt");
  s_out << "foo\n" << std::endl; 
  return 0
}

Что компилируется, но, когда я запускаю, это вызывает ошибку сегментации. Я думал, что проблема вызвана выходом unique_ptr из области видимости. Поэтому я попытался немного изменить main до

int main() {
   stream_ptr ofile = create_safe_stream("foo.txt");
   std::ostream& s_out = *ofile;
   s_out << "foo\n"; 
}

, который снова работает.

ВОПРОС

Есть ли способ не использовать промежуточную переменную, такую ​​как ofile, и делать все в строке?

EDIT

Функция create_safe_stream - это игрушечная модель , что я хочу , то есть эта функция может возвращать либо std::ofstream в этот файл, либо std::cout, поэтому я думаю, что мне действительно нужно вернуть указатель на базовый класс std::ostream. Как я могу это сделать?

1 Ответ

3 голосов
/ 14 июня 2019

Ваше предположение верно.create_safe_stream возвращает std::unique_ptr, который немедленно выходит из области видимости, и, таким образом, необработанный ресурс, который он хранит, равен deleted и пытается использовать его как UB.

Способ не использовать промежуточную переменную и делать этовсе в одной строке, просто возвращая объект std::ofstream вместо:

std::ofstream create_safe_stream(const char* filename) {
    return std::ofstream {filename};
}

int main() {
  std::ostream s_out = create_safe_stream("foo.txt");
  s_out << "foo\n" << std::endl; 
  return 0;
}
...