Re: [問題] 請問char**array的問題
※ 引述《Keitaro (動き出す時間...)》之銘言:
: 開發平台(Platform): (Ex: Win10, Linux, ...)
: Ubuntu 18.04 LTS
: 編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出)
: gcc
: 程式碼(Code):(請善用置底文網頁, 記得排版,禁止使用圖檔)
: https://ideone.com/jugcYC
: 重新上傳完整原始碼
後面恕刪, 因為看起來不像 C++ 所以路過分享一下拙見.
C++ 物件不僅僅是一塊記憶體, 因為生命週期中會有建構子/解構子參與, 簡單
說就是至少會比 C 語言多兩次函式呼叫. 所以撰寫的時候不會輕易地創造物件
, 更不會創完而不用它. array new/delete 這種昂貴的操作其實是蠻罕見的.
你的程式碼主要存在兩個問題:
1. ParseCmd() 的實作沒有彈性, 且效率不高
2. 準備 execve() 引數時做了許多不必要的操作
一般為了減少對 STL container 的依賴, 函式介面會傾向於接受迭代器而不是
特定容器型別物件, 而且除非你很確定要用 std::char_traits<CharT>::eq()
來比較字元是否相等, 不然我們在搜尋的時候傾向於呼叫 STL algorithm 而非
std::basic_string 這種內嵌比較邏輯的型別, 所以通常介面會這樣設計:
template <typename ForwardIterator, typename ForwardSentinel,
typename OutputIterator>
void ParseCmd(ForwardIterator first, ForwardSentinel last,
OutputIterator output) {
while (first != last) {
// call std::find() here
// other code goes here
(*output++) = std::string(first, last);
}
}
#include <iterator>
const std::string str = "-vsync 0 -i file.cfg Compare.yuv";
std::vector<std::string> vCmdSet;
ParseCmd(begin(str), end(str), std::back_inserter(vCmdSet));
std::basic_string 只作為字元的載體, 而不是兼做比較的角色.
再來是準備 execve() 引數的邏輯, 如果非得用 array new/delete 來管理物
件, 那前面呼叫 ParseCmd() 創建一堆 std::string 物件有什麼用呢? 有沒
有辦法重複使用這些物件的內容呢? 實際上你可以呼叫 std::string::data()
成員函式來達成這件事情, 然後把拿到的指標存進另一個 std::vector 內:
#include <algorithm>
#include <iterator>
std::vector<char*> ppCmdArg;
std::transform(begin(vCmdSet), end(vCmdSet),
std::back_inserter(ppCmdArg),
[](std::string& s) { return data(s); });
ppCmdArg.push_back(nullptr);
execve(..., data(ppCmdArg), ...);
這裡用到的概念主要有兩個: 1) std::vector 的 data() 成員函式會回傳第
0 個元素的位址, 而且每個成員的位址保證是連續的, 所以回傳的東西和你用
array new 創建出來的 array of pointers 是相同的; 2) 再者 std::string
的 data() 成員函式會回傳第 0 個字元的位址, 每個字元的位址也是連續的,
而且回傳的記憶體和 c_str() 相同 (只差在 constness), 包含結束字元.
下次撰碼的時候可以試著寫出無 new/delete 的程式碼, 因為偏底層的函式呼
叫次數愈多, 發生錯誤的機會也跟著變多.
--
[P1389R1] Standing Document for SG20: Guidelines for Teaching
C++ to Beginners
https://wg21.link/p1389r1
SG20 Education and Recommended Videos for Teaching C++
https://www.cjdb.com.au/sg20-and-videos
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 123.193.76.216 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1605102909.A.FC2.html
→
11/11 22:28,
3年前
, 1F
11/11 22:28, 1F
→
11/11 22:28,
3年前
, 2F
11/11 22:28, 2F
→
11/11 22:28,
3年前
, 3F
11/11 22:28, 3F
STL container 預設會用 std::allocator<T> 來做配置, 以物件的生命週期來
看, 呼叫的介面先後順序如下:
1. allocate()
2. construct()
3. destroy()
4. deallocate()
1 ~ 2 的使用效果和 operator new + placement new 相同, 並非使用 array
new, 差別在於元素是需要用到的時候才建構, 而非一次全部建構好, 這也是為
什麼如 std::vector 會有 capacity() 及 size() 兩種不同用途的成員函式.
說 new 會產生 raw pointer 那不會是什麼太大問題, 因為使用者可以選擇重
載 new/delete, 只要在重載版本裡做好物件管理即可.
→
11/11 23:58,
3年前
, 4F
11/11 23:58, 4F
推
11/12 03:48,
3年前
, 5F
11/12 03:48, 5F
→
11/12 03:49,
3年前
, 6F
11/12 03:49, 6F
→
11/12 03:50,
3年前
, 7F
11/12 03:50, 7F
推
11/12 10:10,
3年前
, 8F
11/12 10:10, 8F
是的, 你沒看錯
→
11/12 22:49,
3年前
, 9F
11/12 22:49, 9F
→
11/12 22:49,
3年前
, 10F
11/12 22:49, 10F
你知道 operator new 以及 operator new[] (俗稱 array new) 的差異嗎?
遇到沒有 default constructor 的型別初始化會怎麼進行?
→
11/13 01:56,
3年前
, 11F
11/13 01:56, 11F
昂貴的原因在於物件的建構方式.
如同陣列般, 元素的建構是彼此相依的, 除了獲取記憶體的時間成本; 也額外
付出了第 1 個元素開始建構到第 n - 1 個元素結束建構的時間 (n 為陣列大
小), 我們才能開始存取第 0 個元素.
為了使用 operator new[] 來建構大量物件, 使用者還必須提供成本較低的
default ctor, 讓型別支援 two-phase initialization, 也提高程式碼複雜度
所以物件分開建構與否直接影響程式的執行效率, 從 C++17 開始新增多種記憶
體管理介面如 std::byte, std::uninitialized_*() 系列函式, 即是為了完善
這部分的開發.
推
11/13 10:40,
3年前
, 12F
11/13 10:40, 12F
→
11/13 11:30,
3年前
, 13F
11/13 11:30, 13F
→
11/13 11:30,
3年前
, 14F
11/13 11:30, 14F
→
11/13 11:30,
3年前
, 15F
11/13 11:30, 15F
如果是 trival default ctor 就不會有什麼成本.
但從 C++11 開始有執行緒的觀念; C++17 開始有 executor 平行處理的觀念,
在使用 operator new[] 這類操作以前都要思考是否有必要排隊循序執行.
※ 編輯: poyenc (61.216.75.43 臺灣), 11/13/2020 12:04:52
推
11/13 13:03,
3年前
, 16F
11/13 13:03, 16F
推
11/13 22:23,
3年前
, 17F
11/13 22:23, 17F
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 2 之 2 篇):