文章目录
取模
对-1取模是现将-1加上除数的整数倍大于零后再取模。
Timer()
变量
float _elapsed; // 渡过的时间.
bool _runForever; // 状态变量,标记是否永远的运行。
bool _useDelay; // 状态变量,标记是否使用延迟
unsigned int _timesExecuted; // 记录已经执行了多少次。
unsigned int _repeat; // 定义要执行的总次数,0为1次 1为2次 ……
float _delay; // 延迟多少秒,是指在触发之前的延迟,在触发之后叫间隔,使用interval设置
float _interval; // 时间间隔。
_scheduler(nullptr)
, _elapsed(-1)
, _runForever(false)
, _useDelay(false)
, _timesExecuted(0)
, _repeat(0)
, _delay(0.0f)
, _interval(0.0f)
, _aborted(false)
设置定时器Timer()
void Timer::setupTimerWithInterval(float seconds, unsigned int repeat, float delay)
{
_elapsed = -1; //=-1表示是第一次进入函数,后面的再Update函数中会有初始化操作
_interval = seconds;
_delay = delay;
_useDelay = (_delay > 0.0f) ? true : false;
_repeat = repeat;
_runForever = (_repeat == CC_REPEAT_FOREVER) ? true : false; //CC_REPEAT_FOREVER == -1
_timesExecuted = 0;
}
void Timer::update(float dt)
{
if (_elapsed == -1) //表示第一次进入Update方法,进行初始化
{
_elapsed = 0; //已执行时间
_timesExecuted = 0; //执行次数
return;
}
// accumulate elapsed time
_elapsed += dt; //记录累计度过的时间
// deal with delay
if (_useDelay)
{
if (_elapsed < _delay) // 还没有完成延时
{
return;
}
_timesExecuted += 1; // important to increment before call trigger
trigger(_delay); // 【回调函数】
_elapsed = _elapsed - _delay; //此时记录的是开始执行之后度过的时间
_useDelay = false; //延迟结束
// after delay, the rest time should compare with interval
if (isExhausted()) //不永远执行并且已经执行完了重复次数
{ //unschedule timer
cancel();
return;
}
}
// if _interval == 0, should trigger once every frame
float interval = (_interval > 0) ? _interval : _elapsed; //正常来说interval都是大于零的,如果interval小于零,那就使用度过的时间来代替间隔时间
//如果度过的时间比间隔要大才会执行
while ((_elapsed >= interval) && !_aborted)
{
_timesExecuted += 1; // important to increment before call trigger
trigger(interval); // 【回调函数】
_elapsed -= interval; //记录剩余时间
if (isExhausted()) //不永远执行并且已经执行完了重复次数
{
cancel();
break;
}
if (_elapsed <= 0.f) //间隔时间等于度过的时间
{
break;
}
}
}
一些成员函数
bool TimerTargetSelector::initWithSelector(Scheduler* scheduler, SEL_SCHEDULE selector, Ref* target, float seconds, unsigned int repeat, float delay)
{
_scheduler = scheduler;
_target = target;
_selector = selector; //selector没有set方法,通过此方法来初始化
setupTimerWithInterval(seconds, repeat, delay);
return true;
}
void TimerTargetSelector::trigger(float dt) //调用回调函数
{
if (_target && _selector)
{
(_target->*_selector)(dt);
}
}
void TimerTargetSelector::cancel()
{
_scheduler->unschedule(_selector, _target);
}
class CC_DLL TimerTargetCallback : public Timer
{
public:
TimerTargetCallback();
// Initializes a timer with a target, a lambda and an interval in seconds, repeat in number of times to repeat, delay in seconds.
bool initWithCallback(Scheduler* scheduler, const ccSchedulerFunc& callback, void *target, const std::string& key, float seconds, unsigned int repeat, float delay);
const ccSchedulerFunc& getCallback() const { return _callback; }
const std::string& getKey() const { return _key; }
virtual void trigger(float dt) override;
virtual void cancel() override;
protected:
void* _target;
ccSchedulerFunc _callback;
std::string _key;
};
//初始化
bool TimerTargetCallback::initWithCallback(Scheduler* scheduler, const ccSchedulerFunc& callback, void *target, const std::string& key, float seconds, unsigned int repeat, float delay)
{
_scheduler = scheduler;
_target = target;
_callback = callback;
_key = key;
setupTimerWithInterval(seconds, repeat, delay);
return true;
}
//调用回调函数
void TimerTargetCallback::trigger(float dt)
{
if (_callback)
{
_callback(dt);
}
}
//
void TimerTargetCallback::cancel()
{
_scheduler->unschedule(_key, _target);
Scheduler()
经常使用的调度器是:
schedulerUpdate()
scheduler(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay)
scheduleOnce(SEL_SCHEDULE selector, float delay)
变量
pause:启用或暂停此方法。暂停(false),启用(true)
interval:每隔“interval”秒调用一次方法,如果为0,则每一帧都调用,当为0时,建议使用schedulerUpdate。
repeat:触发一次事件后还会触发的次数,为0时触发一次
delay:延迟多少秒,是指在触发之前的延迟,在触发之后叫间隔,使用interval设置
key:用于取消定时器
初始化
typedef struct _listEntry
{
struct _listEntry *prev, *next;
ccSchedulerFunc callback;
void *target;
int priority;
bool paused;
bool markedForDeletion; // selector will no longer be called and entry will be removed at end of the next tick
} tListEntry;
//内置的update定时器
typedef struct _hashUpdateEntry
{
tListEntry **list; // Which list does it belong to ?
tListEntry *entry; // entry in the list
void *target;
ccSchedulerFunc callback;
UT_hash_handle hh;
} tHashUpdateEntry;
// 自定义定时器
typedef struct _hashSelectorEntry
{
ccArray *timers;
void *target;
int timerIndex;
Timer *currentTimer;
bool currentTimerSalvaged;
bool paused;
UT_hash_handle hh;
} tHashTimerEntry;
float _timeScale;
struct _listEntry *_updatesNegList; // list of priority < 0 三种优先级
struct _listEntry *_updates0List; // list priority == 0
struct _listEntry *_updatesPosList; // list priority > 0
struct _hashUpdateEntry *_hashForUpdates; // hash used to fetch quickly the list entries for pause,delete,etc
std::vector<struct _listEntry *> _updateDeleteVector; // the vector holds list entries that needs to be deleted after update
// Used for "selectors with interval"
struct _hashSelectorEntry *_hashForTimers;
struct _hashSelectorEntry *_currentTarget;
bool _currentTargetSalvaged;
// If true unschedule will not remove anything from a hash. Elements will only be marked for deletion.
bool _updateHashLocked;
//初始化
Scheduler::Scheduler(void)
: _timeScale(1.0f) //播放速度为1.0
, _updatesNegList(nullptr) //
, _updates0List(nullptr)
, _updatesPosList(nullptr)
, _hashForUpdates(nullptr)
, _hashForTimers(nullptr)
, _currentTarget(nullptr)
, _currentTargetSalvaged(false)
, _updateHashLocked(false)
#if CC_ENABLE_SCRIPT_BINDING
, _scriptHandlerEntries(20)
#endif
{
// I don't expect to have more than 30 functions to all per frame
//预开辟30个空间,且不希望超过30个函数
_functionsToPerform.reserve(30);
}
哈希表
#include "base/uthash.h"
typedef struct UT_hash_handle {
struct UT_hash_table *tbl;
void *prev; /* prev element in app order */
void *next; /* next element in app order */
struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
struct UT_hash_handle *hh_next; /* next hh in bucket order */
void *key; /* ptr to enclosing struct's key */
unsigned keylen; /* enclosing struct's key len */
unsigned hashv; /* result of hash-fcn(key) */
} UT_hash_handle;
HASH_FIND_PTR(head,findptr,out)
HASH_ADD_PTR(head,ptrfield,add)
HASH_DEL(head,delptr)
//不同优先级的update定时器的双向链表
typedef struct _listEntry
{
struct _listEntry *prev, *next;
ccSchedulerFunc callback;
void *target;
int priority;
bool paused;
bool markedForDeletion; // selector will no longer be called and entry will be removed at end of the next tick
} tListEntry;
//内置的update定时器
typedef struct _hashUpdateEntry
{
tListEntry **list; // Which list does it belong to ?
tListEntry *entry; // entry in the list
void *target;
ccSchedulerFunc callback;
UT_hash_handle hh;
} tHashUpdateEntry;
//自定义的定时器
typedef struct _hashSelectorEntry
{
ccArray *timers; //如下
void *target;
int timerIndex;
Timer *currentTimer;
bool paused;
UT_hash_handle hh;
} tHa
typedef struct _ccArray {
ssize_t num, max;
Ref** arr;
} ccArray;
void ccArrayAppendObject(ccArray *arr, Ref* object)
{
CCASSERT(object != nullptr, "Invalid parameter!");
object->retain();
arr->arr[arr->num] = object;
arr->num++;//序号+1
}
构造函数schedule()
//重载版本① 更新选择器 //Ref *target
void Scheduler::schedule(SEL_SCHEDULE selector, Ref *target, float interval, unsigned int repeat, float delay, bool paused)
{
CCASSERT(target, "Argument target must be non-nullptr");
//用来记录一个Ref对象加载的所有timer
tHashTimerEntry *element = nullptr;
//_hashForTimers是用来记录tHashTimerEntry头结点的指针
//在_hashForTimers链表中查找与target相等的元素,返回一个element
//#define HASH_FIND_PTR(head,findptr,out)
HASH_FIND_PTR(_hashForTimers, &target, element);
//判断有没有找到
if (! element)
{
//为空则先分配空间
element = (tHashTimerEntry *)calloc(sizeof(*element), 1);
//把链表的target指向形参target(把形参的target加入链表)
element->target = target;
//再次查找获取链表中的”element“
HASH_ADD_PTR(_hashForTimers, target, element);
+
// Is this the 1st element ? Then set the pause level to all the selectors of this target
//给获取到的element设置paused的状态
element->paused = paused;
}
//target已经加入链表了,判断paused的状态是否设定成功
else
{
CCASSERT(element->paused == paused, "element's paused should be paused.");
}
//判断定时器列表的状态,如果为空则分配空间
if (element->timers == nullptr)
{
element->timers = ccArrayNew(10);
}
else
{
//循环定时器结构中的成员
for (int i = 0; i < element->timers->num; ++i)
{
//获取其中的定时器对象
TimerTargetSelector *timer = dynamic_cast<TimerTargetSelector*>(element->timers->arr[i]);
//如果定义过定时器,则重新设置interval, repeat, delay
if (timer && !timer->isExhausted() && selector == timer->getSelector())
{
CCLOG("CCScheduler#schedule. Reiniting timer with interval %.4f, repeat %u, delay %.4f", interval, repeat, delay);
timer->setupTimerWithInterval(interval, repeat, delay);
return;
}
}
//检查ccArray的内存,确定可以再添加一个timers
ccArrayEnsureExtraCapacity(element->timers, 1);
}
//创建了一个新的TimerTargetSelector对象(timer),用上面处理过的实参对其初始化,并且加到定时器列表(timers)中
TimerTargetSelector *timer = new (std::nothrow) TimerTargetSelector();
timer->initWithSelector(this, selector, target, interval, repeat, delay);
ccArrayAppendObject(element->timers, timer);//object->retain();
timer->release();
}
//重载版本②//使用回调函数callback 多了 形参key和repeat //自定义选择器 void *target
void Scheduler::schedule(const ccSchedulerFunc& callback, void *target, float interval, unsigned int repeat, float delay, bool paused, const std::string& key)
{
CCASSERT(target, "Argument target must be non-nullptr");
CCASSERT(!key.empty(), "key should not be empty!");
tHashTimerEntry *element = nullptr;
HASH_FIND_PTR(_hashForTimers, &target, element);
if (! element)
{
element = (tHashTimerEntry *)calloc(sizeof(*element), 1);
element->target = target;
HASH_ADD_PTR(_hashForTimers, target, element);
// Is this the 1st element ? Then set the pause level to all the selectors of this target
element->paused = paused;
}
else
{
CCASSERT(element->paused == paused, "element's paused should be paused!");
}
if (element->timers == nullptr)
{
element->timers = ccArrayNew(10);
}
else
{
for (int i = 0; i < element->timers->num; ++i)
{
TimerTargetCallback *timer = dynamic_cast<TimerTargetCallback*>(element->timers->arr[i]);
if (timer && !timer->isExhausted() && key == timer->getKey())
{
CCLOG("CCScheduler#schedule. Reiniting timer with interval %.4f, repeat %u, delay %.4f", interval, repeat, delay);
timer->setupTimerWithInterval(interval, repeat, delay);
return;
}
}
ccArrayEnsureExtraCapacity(element->timers, 1);
}
TimerTargetCallback *timer = new (std::nothrow) TimerTargetCallback();
timer->initWithCallback(this, callback, target, key, interval, repeat, delay);
ccArrayAppendObject(element->timers, timer);
timer->release();
}
//重载版本③ //永远执行 repeat = CC_REPEAT_FOREVER
void Scheduler::schedule(const ccSchedulerFunc& callback, void *target, float interval, bool paused, const std::string& key)
{
this->schedule(callback, target, interval, CC_REPEAT_FOREVER, 0.0f, paused, key);
}
//重载版本④ //永远执行 repeat = CC_REPEAT_FOREVER
void Scheduler::schedule(SEL_SCHEDULE selector, Ref *target, float interval, bool paused)
{
this->schedule(selector, target, interval, CC_REPEAT_FOREVER, 0.0f, paused);
}
开启定时器Update()
/*
void Node::scheduleUpdate()
{
scheduleUpdateWithPriority(0);
}
*/
//每帧执行一次,默认优先级为0,优先级越小越先执行
void Node::scheduleUpdateWithPriority(int priority)
{
_scheduler->scheduleUpdate(this, priority, !_running);
}
//默认优先级为0,在所有自定义方法之前执行
template <class T>
void scheduleUpdate(T *target, int priority, bool paused)
{
this->schedulePerFrame([target](float dt){
target->update(dt);
}, target, priority, paused);
}
void Scheduler::schedulePerFrame(const ccSchedulerFunc& callback, void *target, int priority, bool paused)
{
//定义一个hash链表对象
tHashUpdateEntry *hashElement = nullptr;
//查找target,结果通过hashElement返回
HASH_FIND_PTR(_hashForUpdates, &target, hashElement);
//如果找到了
if (hashElement)
{
// change priority: should unschedule it first
//检查优先级是否已经被修改,如果还未修改,先取消修改的计划;
//如果已经被修改,则提示不要重复执行修改操作
if (hashElement->entry->priority != priority)
{
unscheduleUpdate(target);
}
else
{
// don't add it again
CCLOG("warning: don't update it again");
return;
}
}
// most of the updates are going to be 0, that's way there
// is an special list for updates with priority 0
//然后将其加入到对应优先级的链表中
if (priority == 0)
{
appendIn(&_updates0List, callback, target, paused);//如下
}
else if (priority < 0)
{
priorityIn(&_updatesNegList, callback, target, priority, paused);//如下
}
else
{
// priority > 0
priorityIn(&_updatesPosList, callback, target, priority, paused);
}
}
//appendIn()用于添加默认优先级的
void Scheduler::appendIn(_listEntry **list, const ccSchedulerFunc& callback, void *target, bool paused)
{
//新建优先级更新链表
tListEntry *listElement = new (std::nothrow) tListEntry();
listElement->callback = callback;
listElement->target = target;
listElement->paused = paused;
listElement->priority = 0;
listElement->markedForDeletion = false;
//把listElement加到优先级为0的list中
DL_APPEND(*list, listElement);
// update hash entry for quicker access
//创建一个hash链表指针对象
tHashUpdateEntry *hashElement = (tHashUpdateEntry *)calloc(sizeof(*hashElement), 1);
hashElement->target = target;
hashElement->list = list;
hashElement->entry = listElement;
memset(&hashElement->hh, 0, sizeof(hashElement->hh));
//把hashElement添加到_hashForUpdates中
HASH_ADD_PTR(_hashForUpdates, target, hashElement);
}
//priorityIn()用于添加指定优先级
void Scheduler::priorityIn(tListEntry **list, const ccSchedulerFunc& callback, void *target, int priority, bool paused)
{
//同上
tListEntry *listElement = new (std::nothrow) tListEntry();
listElement->callback = callback;
listElement->target = target;
listElement->priority = priority;
listElement->paused = paused;
listElement->next = listElement->prev = nullptr;
listElement->markedForDeletion = false;
//判断优先级<0的链表是不是空的
if (! *list)
{
//是空的直接添加
DL_APPEND(*list, listElement);
}
else
{
//设置一个add表示还未添加完成
bool added = false;
for (tListEntry *element = *list; element; element = element->next)
{
//如果添加的元素的优先级 < 被循环到的元素的优先级,
//说明插入的元素优先级更高,则会被插入到循环的这个元素之前
if (priority < element->priority)
{
if (element == *list)
{
DL_PREPEND(*list, listElement);
}
else
{
//tListEntry *element = *list的备选路径
listElement->next = element;
listElement->prev = element->prev;
element->prev->next = listElement;
element->prev = listElement;
}
//添加完成了
added = true;
break;
}
}
// Not added? priority has the higher value. Append it.
//是否添加完成(未完成说明插入的元素在链表中的优先级最低,插入到链表最后)
if (! added)
{
DL_APPEND(*list, listElement);
}
}
// update hash entry for quick access
//同上
tHashUpdateEntry *hashElement = (tHashUpdateEntry *)calloc(sizeof(*hashElement), 1);
hashElement->target = target;
hashElement->list = list;
hashElement->entry = listElement;
memset(&hashElement->hh, 0, sizeof(hashElement->hh));
HASH_ADD_PTR(_hashForUpdates, target, hashElement);
}
析构函数~Update()
void Scheduler::unschedule(const std::string &key, void *target)
{
// explicit handle nil arguments when removing an object
if (target == nullptr || key.empty())
{
return;
}
//CCASSERT(target);
//CCASSERT(selector);
tHashTimerEntry *element = nullptr;
HASH_FIND_PTR(_hashForTimers, &target, element);
if (element)
{
for (int i = 0; i < element->timers->num; ++i)
{
TimerTargetCallback *timer = dynamic_cast<TimerTargetCallback*>(element->timers->arr[i]);
//找到要移除的timer
if (timer && key == timer->getKey())
{
if (timer == element->currentTimer && (! timer->isAborted()))
{
timer->retain();//+1
timer->setAborted();//设置延迟释放,下面还要继续访问
}
//在这里调用CC_SAFE_RELEASE -1
ccArrayRemoveObjectAtIndex(element->timers, i, true);
// update timerIndex in case we are in tick:, looping over the actions
//个数-1
if (element->timerIndex >= i)
{
element->timerIndex--;
}
//timers里面没有timer了
if (element->timers->num == 0)
{
//标记需要被删除,在刷新函数中执行移除操作
if (_currentTarget == element)
{
_currentTargetSalvaged = true;
}
else
{
//链表中移除 移除之后是安全的了,回到Scheduler::update()中再release()释放
removeHashElement(element);
}
}
return;
}
}
}
}
Update()
void Scheduler::update(float dt)
{
//状态锁
_updateHashLocked = true;
//调整时间速率
if (_timeScale != 1.0f)
{
dt *= _timeScale;
}
//
// Selector callbacks
//
// Iterate over all the Updates' selectors
tListEntry *entry, *tmp;
// updates with priority < 0
//先执行优先级高的 priority < 0
DL_FOREACH_SAFE(_updatesNegList, entry, tmp)
{
//对没有暂停的和没有被标记需要删除的执行回调函数
if ((! entry->paused) && (! entry->markedForDeletion))
{
entry->callback(dt);
}
}
// updates with priority == 0
DL_FOREACH_SAFE(_updates0List, entry, tmp)
{
if ((! entry->paused) && (! entry->markedForDeletion))
{
entry->callback(dt);
}
}
// updates with priority > 0
DL_FOREACH_SAFE(_updatesPosList, entry, tmp)
{
if ((! entry->paused) && (! entry->markedForDeletion))
{
entry->callback(dt);
}
}
// Iterate over all the custom selectors
//遍历自定义的定时器
for (tHashTimerEntry *elt = _hashForTimers; elt != nullptr; )
{
_currentTarget = elt; //标记执行到了那个target对象
_currentTargetSalvaged = false; //设置定时器为可用状态
if (! _currentTarget->paused)
{
// The 'timers' array may change while inside this loop
//遍历当前对象的所有定时器
for (elt->timerIndex = 0; elt->timerIndex < elt->timers->num; ++(elt->timerIndex))
{
//标记执行到了那个timer对象
elt->currentTimer = (Timer*)(elt->timers->arr[elt->timerIndex]);
//如果已经被弃用
CCASSERT( !elt->currentTimer->isAborted(),
"An aborted timer should not be updated" );
//
elt->currentTimer->update(dt);//执行定时器的update()!! 在这里执行定时器的回调函数
//如果被弃用了就释放它 执行了上面一条语句之后,已经被从链表中移除了,这时候释放才是安全的
if (elt->currentTimer->isAborted())
{
// The currentTimer told the remove itself. To prevent the timer from
// accidentally deallocating itself before finishing its step, we retained
// it. Now that step is done, it's safe to release it.
elt->currentTimer->release();
}
//当前执行到的timer对象置空
elt->currentTimer = nullptr;
}
}
// elt, at this moment, is still valid
// so it is safe to ask this here (issue #490)
//链表继续往后访问
elt = (tHashTimerEntry *)elt->hh.next;
// only delete currentTarget if no actions were scheduled during the cycle (issue #481)
//如果被标记弃用并且里面没有timer了,就移除它(定时器已经执行完成了)
if (_currentTargetSalvaged && _currentTarget->timers->num == 0)
{
removeHashElement(_currentTarget);
}
}
// delete all updates that are removed in update
//移除所有标记为要删除的update定时器元素
for (auto &e : _updateDeleteVector)
delete e;
//清空待删除数组
_updateDeleteVector.clear();
//移除状态锁
_updateHashLocked = false;
//执行到的target对象置空
_currentTarget = nullptr;
#if CC_ENABLE_SCRIPT_BINDING
//
// Script callbacks
//
// Iterate over all the script callbacks
if (!_scriptHandlerEntries.empty())
{
for (auto i = _scriptHandlerEntries.size() - 1; i >= 0; i--)
{
SchedulerScriptHandlerEntry* eachEntry = _scriptHandlerEntries.at(i);
if (eachEntry->isMarkedForDeletion())
{
_scriptHandlerEntries.erase(i);
}
else if (!eachEntry->isPaused())
{
eachEntry->getTimer()->update(dt);
}
}
}
#endif
//
// Functions allocated from another thread
//
// Testing size is faster than locking / unlocking.
// And almost never there will be functions scheduled to be called.
if( !_functionsToPerform.empty() ) {
_performMutex.lock();
// fixed #4123: Save the callback functions, they must be invoked after '_performMutex.unlock()', otherwise if new functions are added in callback, it will cause thread deadlock.
auto temp = std::move(_functionsToPerform);
_performMutex.unlock();
for (const auto &function : temp) {
function();
}
}
}
removeUpdateFromHash()
void Scheduler::unscheduleUpdate(void *target)
{
if (target == nullptr)
{
return;
}
tHashUpdateEntry *element = nullptr;
HASH_FIND_PTR(_hashForUpdates, &target, element);
if (element)
this->removeUpdateFromHash(element->entry); //
}
void Scheduler::removeUpdateFromHash(struct _listEntry *entry)
{
tHashUpdateEntry *element = nullptr;
HASH_FIND_PTR(_hashForUpdates, &entry->target, element);
if (element)
{
// list entry
DL_DELETE(*element->list, element->entry);
if (!_updateHashLocked)
CC_SAFE_DELETE(element->entry);
else
{
element->entry->markedForDeletion = true;
_updateDeleteVector.push_back(element->entry); //
}
// hash entry
HASH_DEL(_hashForUpdates, element);
free(element);
}
}
一些成员函数
//通过key和target来判断当前对象是否在定时器中
bool isScheduled(const std::string& key, const void *target) const;
//判断条件不同
bool isScheduled(SEL_SCHEDULE selector, const Ref *target) const;
//恢复一个对象的定时器
void resumeTarget(void *target);
//查询一个对象的定时器装状态
bool isTargetPaused(void *target);
//暂停所有的定时器
std::set<void*> pauseAllTargets();
//恢复所有的定时器
void resumeTargets(const std::set<void*>& targetsToResume);
补充
1、为什么使用colloc不使用malloc?
究其根本是malloc和colloc区别的原因,
使用
malloc:(type*)malloc(size) 分配一个size大小的内存空间返回type类型的指针指向内存的首地址
colloc:(type*)colloc(n,size) 分配n个size大小的连续内存空间返回type类型的指针指向第一个内存的首地址
最大的区别是:malloc只分配内存空间不做初始化,原先内存中的数据依然存在,可能会造成数据错误;colloc分配空间后进行初始化,将分配的空间都初始化为0,避免了数据错误。
2、std::move
std::string str = "Hello";
std::vector<std::string> v;
v.push_back(str);
std::cout<<v[0]; //输出hello
std::cout<<str; //输出hello
v.push_back(std::move(str));
std::cout<<v[0]; //输出hello
std::cout<<v[1]; //输出hello
std::cout<<str; //输出为空