Abstract
I have little C/C++ skills. I've learned programming mainly with Java, and so I chose C++ (targeting C++11) as the language to learn better. In my current C++ project, I have to use the discount C library for its Markdown functions.
To explain briefly my code: the member variable std::string markdown_
is the Markdown I want to "compile" to HTML. To do so, I have to use the following functions from discount:
MMIOT *mkd_string(char *string, int size, int flags);
int mkd_compile(MMIOT *document, int flags);
int mkd_document(MMIOT *document, char **doc);
mkd_css
andmkd_toc
are alikemkd_document
Questions
As you see, I need to copy the
markdown_
string and make it achar*
. To do so, I used astd::vector
as suggested in Converting an std::string into a char array, but I would like to know if doing it this way is appropriate in my case, or if there are other ways to achieve that.MMIOT *mkd_string(char *string, int size, int flags);
is defined in the main page to returnnull
on error. Is it correct to usenullptr
like I do in the following code to check the return value?Do you have suggestions to improve this code, or does it looks good?
Code extract
const std::string Markdown::error_msg_mkd_string = "libmarkdown failed to "
"parse the following Markdown:\n";
void Markdown::compile()
{
MMIOT* doc;
int size;
char *cstr_buff;
int flags = MKD_TOC|MKD_SAFELINK|MKD_EXTRA_FOOTNOTE;
std::vector<char> buff(markdown_.cbegin(), markdown_.cend());
doc = mkd_string(&buff[0], buff.size(), flags);
if(doc == nullptr)
throw std::runtime_error(
std::string(error_msg_mkd_string)
.append(&buff[0], buff.size())
);
mkd_compile(doc, flags);
// It is not a bad practice to reuse 'size' and 'cstr_buff' like in the
// following code, or is it?
size = mkd_css(doc, &cstr_buff);
css_.assign(cstr_buff, size);
size = mkd_document(doc, &cstr_buff);
html_.assign(cstr_buff, size);
size = mkd_toc(doc, &cstr_buff);
toc_.assign(cstr_buff, size);
mkd_cleanup(doc);
}
2 Answers 2
- If
mkd_string
accepts aconst char*
, then you are better off using astd::string
and its methodc_str()
to pass the value to the function. Otherwise your solution is correct. Yes. See this answer for the why. Or build this code (tested with
g++ -std=c++0x
, gcc version 4.6):#include <iostream> int main() { if (NULL == nullptr) std::cout << "NULL == nullptr\n"; }
Declare the variable immediately before using it, possibly also defining it. This reduces its scope to the minimum, helps the reader/maintainer of the code understanding what the variable is for, and avoids terrible errors deriving from forgetting to initialize variables. (This should also provide you with some guideline for the question about re-using the same variable twice in the same block.)
std::string
has a built-in function (c_str
) to convert the std::string
to a const char*
. It returns a pointer to the internal character string (terminated by a 0).
std::string str;
const char* cstr = str.c_str();
If you need a non-const char*
, do not cast out the const. That will cause a bug. Instead, copy it to a new non-const char*
.
char* cstrCopy = new char [str.length()+1];
std::strcpy (cstrCopy, str.c_str());
const
could save you a lot of head-ache. In the functionMMIOT *mkd_string(char *string, int size, int flags);
ischar *string
modified/changed in this function at all? \$\endgroup\$mkd_string
takes indeed aconst char*
(see mkdio.c) but the function is declared withoutconst
in the library documentation. @ahenderson \$\endgroup\$mkd_string(markdown_.c_str(), markdown_.size(), flags);
. Stringc_str()
returns the string as aconst char *
. \$\endgroup\$